package com.yaodian100.ec.order.service.impl;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.admin.entity.User;
import com.yaodian100.core.admin.service.UserService;
import com.yaodian100.core.admin.utils.AdminHelper;
import com.yaodian100.core.batch.service.BatchJobService;
import com.yaodian100.core.common.dao.ObjectDao;
import com.yaodian100.core.common.dao.impl.CommonCriteria;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.service.BaseManager;
import com.yaodian100.core.common.service.DomainService;
import com.yaodian100.core.common.service.impl.DomainServiceImpl;
import com.yaodian100.core.common.utils.DateUtil;
import com.yaodian100.core.common.utils.JspUtil;
import com.yaodian100.core.common.utils.ServerValue;
import com.yaodian100.core.common.utils.StringUtils;
import com.yaodian100.core.logger.service.LogService;
import com.yaodian100.core.mail.entity.Mail;
import com.yaodian100.core.mail.service.MailService;
import com.yaodian100.core.menu.entity.Menu;
import com.yaodian100.core.menu.entity.Option;
import com.yaodian100.core.sms.service.SmsService;
import com.yaodian100.core.template.service.TemplateService;
import com.yaodian100.crm.cs.service.CsService;
import com.yaodian100.crm.workorder.entity.LogisticProvider;
import com.yaodian100.ec.campaign.entity.Campaign;
import com.yaodian100.ec.campaign.entity.CampaignExtend;
import com.yaodian100.ec.campaign.entity.CampaignProduct;
import com.yaodian100.ec.campaign.service.CampaignProductService;
import com.yaodian100.ec.campaign.service.CampaignService;
import com.yaodian100.ec.category.service.CategoryService;
import com.yaodian100.ec.cobranding.Onlylady;
import com.yaodian100.ec.cobranding.entity.DPNStore;
import com.yaodian100.ec.cobranding.service.DPNService;
import com.yaodian100.ec.common.EcConstant;
import com.yaodian100.ec.common.EnvParameters;
import com.yaodian100.ec.coupon.entity.CouponItem;
import com.yaodian100.ec.coupon.service.CouponService;
import com.yaodian100.ec.delivery.entity.ViewDeliveryRule;
import com.yaodian100.ec.delivery.service.DeliveryRuleService;
import com.yaodian100.ec.mailbanner.entity.MailBanner;
import com.yaodian100.ec.mailbanner.service.MailBannerService;
import com.yaodian100.ec.member.entity.Balance;
import com.yaodian100.ec.member.entity.Bonus;
import com.yaodian100.ec.member.entity.Member;
import com.yaodian100.ec.member.entity.VirtualBalance;
import com.yaodian100.ec.member.entity.VirtualBalance.VirtualBalancePayType;
import com.yaodian100.ec.member.entity.VirtualBalance.VirtualBalanceType;
import com.yaodian100.ec.member.service.AddessService;
import com.yaodian100.ec.member.service.MemberService;
import com.yaodian100.ec.order.entity.CsrUpdateOrderLog;
import com.yaodian100.ec.order.entity.OrderBonusCampaign;
import com.yaodian100.ec.order.entity.OrderCreditCardCampaign;
import com.yaodian100.ec.order.entity.OrderMemo;
import com.yaodian100.ec.order.entity.OrderProduct;
import com.yaodian100.ec.order.entity.OrderProductDetail;
import com.yaodian100.ec.order.entity.OrderUserData;
import com.yaodian100.ec.order.entity.Orders;
import com.yaodian100.ec.order.entity.ServiceOrderDetail;
import com.yaodian100.ec.order.entity.ServiceOrderProduct;
import com.yaodian100.ec.order.entity.ServiceOrders;
import com.yaodian100.ec.order.entity.Orders.ORDER_LOGISTIC_PROVIDER_TP;
import com.yaodian100.ec.order.remote.ODetail;
import com.yaodian100.ec.order.remote.OProduct;
import com.yaodian100.ec.order.remote.Order;
import com.yaodian100.ec.order.service.OrderService;
import com.yaodian100.ec.order.service.ServiceOrderService;
import com.yaodian100.ec.payment.service.TransferService;
import com.yaodian100.ec.product.entity.AddPurchaseSetting;
import com.yaodian100.ec.product.entity.Product;
import com.yaodian100.ec.product.entity.ProductTuangouOP;
import com.yaodian100.ec.product.entity.Specification;
import com.yaodian100.ec.product.entity.SpecificationInventory;
import com.yaodian100.ec.product.service.AddPurchaseSettingService;
import com.yaodian100.ec.product.service.AndeProductService;
import com.yaodian100.ec.product.service.ProductService;
import com.yaodian100.ec.shelf.entity.Shelf;
import com.yaodian100.ec.shelf.entity.ShelfTuangou;
import com.yaodian100.ec.shelf.service.ShelfService;
import com.yaodian100.ec.shelf.service.ShelfTuangouService;
import com.yaodian100.ec.shopping.entity.ApplyCampaign;
import com.yaodian100.ec.shopping.entity.CartOrderProduct;
import com.yaodian100.ec.shopping.entity.CartOrderProductDetail;
import com.yaodian100.ec.shopping.entity.CartOrders;
import com.yaodian100.ec.shopping.service.CartOrdersService;
import com.yaodian100.ec.supplierapply.entity.SupplierApply;
import com.yaodian100.ec.supplierapply.service.SupplierApplyService;

public class OrderServiceImpl extends DomainServiceImpl<Orders> implements OrderService, InitializingBean {
	private static final String[] IGNORE_PROPERTIES_WHEN_COPY_FROM_ORDER_DETAIL_TO_SERVICE_DETAIL = new String[] {
			"shippingOid", "shippingLineOid" };
	private static final String order_amount_error1 = "訂單主檔.total_price <> sum(訂單明細 amount)";
	private static final String order_amount_error2 = "訂單主檔.total_price <> sum(訂單商品.total_price)";
	private static final String order_amount_error3 = "sum(訂單商品.amount) <> 訂單主檔.amount";
	private static final String order_amount_error4 = "訂單主檔.must_pay + 訂單主檔.my_wallet + 訂單主檔.bonus +訂單主檔.giftcard_balance <> 訂單主檔.amount + 訂單主檔.shipfare + 訂單主檔.cod_fee + 訂單主檔.installment_fee";

	@Resource
	private BatchJobService batchJobService;
	@Resource
	private TransferService transferService;
	private ObjectDao<OrderProduct> orderProductDao;
	private ObjectDao<OrderProductDetail> orderProductDetailDao;
	private ObjectDao<OrderUserData> ordersUserDataDao;
	private ObjectDao<OrderCreditCardCampaign> orderCreditCardCampaignDao;
	private ObjectDao<OrderMemo> orderMemoDao;
	private ObjectDao<OrderBonusCampaign> orderBonusCampaignDao;
	@Resource
	private TemplateService velocityService;
	@Resource
	private MailService mailService;
	@Resource
	private MemberService memberService;
	@Resource
	private DomainService<Menu> menuService;
	private Menu paymentTpMenu; // 與 getter, setter
	@Resource
	private CartOrdersService cartordersService;
	@Resource
	private BaseManager baseMgr;
	@Resource
	private LogService logService;
	@Resource
	private EnvParameters envParameters;
	@Resource
	private ServiceOrderService serviceOrderService;
	@Resource
	private ProductService productService;
	@Resource
	private CategoryService categoryService;
	@Resource
	private CouponService couponService;
	@Resource
	private CampaignProductService campaignProductService;
	@Resource
	private SmsService smsService;
	@Resource
	private AddessService addressService;
	@Resource
	private CsService csService;
	@Resource
	private ShelfService shelfService;
	@Resource
	private AddPurchaseSettingService addPurchaseSettingService;
	@Resource
	private DPNService dpnService;
	@Resource
	private DeliveryRuleService deliveryRuleService;
	@Resource
	private JdbcTemplate jdbcTemplate;
	@Autowired
	private MailBannerService mailBannerService;
	@Autowired
	private SupplierApplyService supplierApplyService;
	@Autowired
	private ShelfTuangouService tuangouService;
	@Resource
	private UserService userService;
	@Autowired
	private AndeProductService andeProductService;
	@Autowired
	private CampaignService campaignService;

	private final String productUrl = "'http://${memberObj.domainSrc}${sValue.frontContextPath}/product/product.do?productId=${oProdDetail.prodId}&z=${z}&campaignCookie=${applySource}'";
	private final String productNMUrl = "'http://${memberObj.domainSrc}${sValue.frontContextPath}/product/product.do?productId=${oProd.prodId}&z=${z}&campaignCookie=${applySource}'";
	private final String productAddonUrl = "'http://${memberObj.domainSrc}${sValue.frontContextPath}/product/addOnProductInfo.do?productId=${oProd.prodId}&addOnProductId=${oProdDetail.prodId}&capture=true'";
	private final String productPromoteUrl = "'http://${memberObj.domainSrc}${sValue.frontContextPath}/product/promoteProductInfo.do?productId=${oProd.prodId}&promoteUuid=${promote.uuid}&capture=true'";

	private Menu systemValueMenu;

	@Transactional(readOnly = false)
	private void afterOrders(Orders orders, BigDecimal chkVrtBlnc, String cpItemUUID, BigDecimal editBonus,
			BigDecimal chkGiftCard) throws Exception {

		// if (delCartByCartId(cartOrders.getCartId()).equals("success")) {
		// 扣除帳戶餘額
		if (chkVrtBlnc.floatValue() > 0.0f) {
			VirtualBalance vb = new VirtualBalance();
			vb.setMemberId(orders.getMemberId());
			vb.setTrxDate(new Date());
			vb.setTrxType(VirtualBalanceType.EC_ORDER_MAIN.name());
			vb.setTrxAmount(chkVrtBlnc.negate());
			vb.setDescription("支付至订单：<a href=\"" + ServerValue.getFrontContextPath()
					+ "/member/order/page.do?page=detail&orderId=" + orders.getOrderId() + "\">" + orders.getOrderId() + "</a>");
			vb.setTrxTypeId(orders.getOrderId());
			vb.setType(VirtualBalancePayType.VirtualBalance.getValue());
			vb = memberService.saveOrUpdateVirtualBalance(vb);
		}
		// 扣除礼品卡
		if (chkGiftCard.floatValue() > 0.0f) {
			VirtualBalance vbGiftcard = new VirtualBalance();
			vbGiftcard.setMemberId(orders.getMemberId());
			vbGiftcard.setTrxDate(new Date());
			vbGiftcard.setTrxType(VirtualBalanceType.EC_ORDER_MAIN.name());
			vbGiftcard.setTrxAmount(chkGiftCard.negate());
			vbGiftcard.setDescription("支付至订单：<a href=\"" + ServerValue.getFrontContextPath()
					+ "/member/order/page.do?page=detail&orderId=" + orders.getOrderId() + "\">" + orders.getOrderId() + "</a>");
			vbGiftcard.setTrxTypeId(orders.getOrderId());
			vbGiftcard.setType(VirtualBalancePayType.GiftcardBalance.getValue());
			vbGiftcard = memberService.saveOrUpdateVirtualBalance(vbGiftcard);
		}
		// 扣除coupon
		List<OrderProduct> ops = orders.getOrderProduct();
		for (OrderProduct orderP : ops) {
			if (StringUtils.isNotBlank(orderP.getCouponItemId())) {
				couponService.useCoupon(orderP.getCouponItemId(), orders.getMemberId(), orders.getOrderId());
			}
		}
		// 扣除bonus
		if (editBonus.compareTo(BigDecimal.ZERO) == 1) {
			transferService.chargeByBonusTransfer(orders);
		}
		// 扣數量
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("orderId", orders.getOrderId());
		List<OrderProductDetail> orderProductDetails = new ArrayList();
		for (OrderProduct op : orders.getOrderProduct()) {
			orderProductDetails.addAll(op.getOrderProductDetail());
		}
		int updateError = 0;
		StringBuffer updateErrorStr = new StringBuffer();
		for (OrderProductDetail orderProductDetail : orderProductDetails) {
			if (orderProductDetail.getQty() > 0 && !orderProductDetail.getProdSpecName().equals("N选M")) {
				try {
					Integer update = (Integer) baseMgr.executeHql(
							"update SpecificationInventory a set a.modifyDate=sysdate, a.soldInventory = a.soldInventory + ? "
									+ " where (availableInventory + cancelInventory - soldInventory) >= ?"
									+ " and a.productId = ? and specId = ? ", new Object[] { orderProductDetail.getQty(),
									orderProductDetail.getQty(), orderProductDetail.getProdId(),
									Long.parseLong(orderProductDetail.getProdSpecId()) });
					// logService.save(getClass().getSimpleName(), "afterOrders-specInv", specificationInventory);
					if (update == 0) {
						updateError++;
						updateErrorStr.append("商品编号:" + orderProductDetail.getProdId() + "(" + orderProductDetail.getProdName()
								+ "), 规格编号:" + orderProductDetail.getProdSpecId() + "(" + orderProductDetail.getProdSpecName() + "):"
								+ "数量不足！！");
					}
					productService.checkIsSoldOut(orderProductDetail.getProdId());
				} catch (Exception ee) {
					throw new CoreException(orderProductDetail.getProdId() + ":" + orderProductDetail.getProdSpecId() + ":"
							+ "数量更新异常，无法成立部份取消订单！！");
				}
			}
		}
		if (updateError > 0) {
			throw new CoreException("建议一并取消以下商品：" + updateErrorStr.toString());
		}
		// 黑名單或貨到付款建立工单
		if (orders.getOrderSt().equals("00")) {// 00 訂單審核中
			csService.createPayByProductArrive(orders.getMemberId(), orders.getOrderId(), "");
		} else {
			// 高單關懷
			// highPriceOrder(orders.getMemberId(), orders, "高单关怀");

		}
		// logService.save(getClass().getSimpleName(), "afterOrders", orders);
	}

	private void highPriceOrder(String memberId, Orders order, String content) {
		int highPrice = 2000;
		Object[] result = baseMgr.queryByHql("from Option where code=? and menu.key=?", new Object[] { "high_price",
				"SystemValue" });
		if (result != null && result.length > 0) {
			highPrice = Integer.valueOf(((Option) result[0]).getMemo1());
		}
		if (order.getAmount().floatValue() > highPrice) {
			System.out.println("------in highPriceOrder");
			csService.createHighPriceOrder(memberId, order.getOrderId(), content);
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (paymentTpMenu == null) {
			paymentTpMenu = menuService.get("Order.PaymentTp");
		}
	}

	private boolean baseCharge(Orders order, String paymentId, BigDecimal amount) {
		Date paymentDate = DateUtil.getCurrentTime();
		HashMap map = new HashMap();
		map.put("orderId", order.getOrderId());
		map.put("paymentId", paymentId);
		map.put("amount", amount);
		map.put("date", DateUtil.getToday());
		if (order == null) {
			logService.save(this.getClass().getName(), "charge_orderIsNull", map);
			return false;
		}
		// 使用銀行或郵局匯款，應使用btk入賬
		if ("10".equals(order.getPaymentTp()) || "20".equals(order.getPaymentTp())) {
			if (null == transferService.getBankTransfer(paymentId)) {
				logService.save(this.getClass().getName(), "paymentTpIsNotMatch", map);
				return false;
			}
		}
		// 使用第三方支付，應使用第三方紀錄付款
		if ("50".equals(order.getPaymentTp()) || "70".equals(order.getPaymentTp()) || "80".equals(order.getPaymentTp())) {
			if (null == transferService.get(paymentId)) {
				logService.save(this.getClass().getName(), "paymentTpIsNotMatch", map);
				return false;
			}
		}
		if (order.getMustPay().compareTo(amount) != 0) {
			logService.save(this.getClass().getName(), "charge_amountNotMatch", map);
			return false;
		} else {
			try {
				order.setPaymentId(paymentId);
				order.setCash(amount);
				order.setPaymentSt("10");
				order.setOrderSt("20");
				// 通知出货
				// batchJobService.save(Orders.ORDER_BEAN.CREATE.getValue(), toXML(order));
				order.setSyncDt(paymentDate);
				order.setPaymentDt(paymentDate);
				// TODO 发送email付款成功
				sendApplyClaimMail("order.gotMoney", order);
				// sendApplyClaimMail裡面已經有發送簡訊了，不需重複發送
				// Member member = (Member) baseMgr.get(Member.class, order.getMemberId());
				// if (member.getMobile() != null && member.getMobile().length() > 0) {
				// float myWallet = order.getMyWallet() != null ? order.getMyWallet().floatValue() : 0;
				// float mustPay = order.getMustPay() != null ? order.getMustPay().floatValue() : 0;
				// float orderAmount = myWallet + mustPay;
				// String msg = "您好，您在耀点100的订单" + order.getOrderId() + "付款已收到，共计" + JspUtil.currency(orderAmount)
				// + "元，我們将尽快为您确认、处理订单。";
				// smsService.sendSms(member.getMobile(), msg, order.getOrderId());
				// }
				memberService.updateOrder2PayBalance(order.getMemberId());
				order = calcOrderCash(order);
				this.update(order);
				logService.save(this.getClass().getName(), "charge", order);
				return true;
			} catch (CoreException e) {
				logService.save(this.getClass().getName(), "charge_exception", map);
				return false;
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public void cancelUnpaidOrderBySystem(Orders order) throws CoreException {
		order.setOrderSt("80");// cancel order
		this.update(order);
		serviceOrderService.returnInventory(order);
		serviceOrderService.cancelOrderBySystem(order.getOrderId(), "订单" + order.getOrderId() + " 已过期取消", "订单"
				+ order.getOrderId() + " 已过期取消", order.getMemberId(), "SYSTEM", order.getB2eId());// 處理禮券，积分，帳戶餘額
		memberService.updateOrder2PayBalance(order.getMemberId());
		sendMail("order.cancelOrder", "订单" + order.getOrderId() + " 已过期取消", order);

		// cobranding-onlylady

		String domainSrc = order.getDomainSrc();
		if (!domainSrc.endsWith("yaodian100.com")) {
			if (domainSrc.endsWith("onlylady.com")) {
				Onlylady ol = new Onlylady();
				ol.olCancelOrder(order);
			}
		}

	}

	@Override
	@Transactional(readOnly = false)
	public void cancelOrderByCreditCardNotidy(Orders order) throws CoreException {
		order.setOrderSt("80");// cancel order
		this.update(order);
		serviceOrderService.returnInventory(order);
		serviceOrderService.cancelOrderBySystem(order.getOrderId(), "订单" + order.getOrderId() + " 因信用卡风险交易提示而取消", "订单"
				+ order.getOrderId() + " 因信用卡风险交易提示而取消", order.getMemberId(), "SYSTEM", order.getB2eId());// 處理禮券，积分，帳戶餘額
		memberService.updateOrder2PayBalance(order.getMemberId());
		// sendMail("order.cancelOrder", "订单" + order.getOrderId() + " 已过期取消", order);

		// cobranding-onlylady

		String domainSrc = order.getDomainSrc();
		if (!domainSrc.endsWith("yaodian100.com")) {
			if (domainSrc.endsWith("onlylady.com")) {
				Onlylady ol = new Onlylady();
				ol.olCancelOrder(order);
			}
		}

	}

	@Override
	@Transactional(readOnly = false)
	public void completeOrder(String orderId) throws CoreException {

		Orders order = this.get(orderId);
		order.setOrderSt("90");
		this.save(order);

		// cobranding-onlylady
		String domainSrc = order.getDomainSrc();
		if (!domainSrc.endsWith("yaodian100.com")) {
			if (domainSrc.endsWith("onlylady.com")) {
				Onlylady ol = new Onlylady();
				ol.olCompleteOrder(order);
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public boolean changeApply(Long orderProdId) throws CoreException {
		OrderProduct orderProd = orderProductDao.get(orderProdId);
		// TODO Log 换货申请
		orderProd.setChange(true);
		orderProductDao.update(orderProd);
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean charge(String orderId, String paymentId, BigDecimal amount) throws CoreException {

		Orders order = this.get(orderId);
		// logger.debug("order mustPay error:{}", order.getMustPay());
		// logger.debug("order mustPay error:{}", amount);
		// logger.debug("order mustPay equals amount error:{}", order.getMustPay().equals(amount));
		// logger.debug("order mustPay compare amount error:{}", order.getMustPay().compareTo(amount));
		return baseCharge(order, paymentId, amount);
	}

	@Override
	@Transactional(readOnly = false)
	public boolean charge(String orderId, String paymentId, BigDecimal amount, String src) {

		Orders order = this.get(orderId);
		if (orderId.equals(order.getJoinOrders())) {
			// 无合并结帐
			order.setPaymentSrc(src);
			return baseCharge(order, paymentId, amount);
		} else {
			// 合并结帐
			BigDecimal sumAmount = BigDecimal.ZERO;
			for (String o : StringUtils.split(order.getJoinOrders(), ",")) {
				if (!order.getOrderId().equals(o)) {
					order = this.get(o);
				}
				order.setPaymentSrc(src);
				// 每笔结帐金额应当等同 order.mustPay
				baseCharge(order, paymentId, order.getMustPay());
				sumAmount = sumAmount.add(order.getMustPay());
			}
			if (amount.compareTo(sumAmount) == 0) {
				return true;
			} else {
				// sum(order.mustPay) != order.joinMustPay
				throw new CoreException("订单 msutPay 总计与 joinMustPay 不符, joinOrders:" + order.getJoinOrders() + ",joinMustPay:"
						+ order.getJoinMustPay() + ",传入金额:" + amount + ",计算金额:" + sumAmount);
			}
		}
	}

	private void checkOrderStatus(Orders order, String nextStatus) {
		// 判斷狀態是否不正常
		if (order.getOrderSt().equals("35")) {
			// 已经到货不允许更改状态
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		} else if (order.getOrderSt().equals("70")) {
			// 訂單已經 是交易未成功 , 不能更新 狀態
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		} else if (order.getOrderSt().equals("90")) {
			// 訂單已經 完成
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		} else if (order.getOrderSt().equals("80")) {
			// 訂單已取消
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		} else if (order.getOrderSt().equals("81")) {
			// 訂單手動取消
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		} else if (order.getOrderSt().equals("60")) {
			// 訂單無法發貨
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		} else if (order.getOrderSt().equals("61")) {
			// 訂單無法發貨
			throw new RuntimeException("Order(" + order.getOrderId() + ")'s current status:" + order.getOrderSt()
					+ "; want to change to:" + nextStatus);
		}
	}

	private void createCancelServiceOrder(Orders order, String description) {
		// reason type="02"為系統取消
		createServiceOrder(order, description, ServiceOrders.SERVICE_TYPE.CANCEL.getValue(),
				ServiceOrders.REASON_TYPE.SYSTEM_CANCEL.getValue());
		// 退庫存
		serviceOrderService.returnInventory(order);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#createOrderWithPay(com.yaodian100.ec.shopping.entity.CartOrders,
	 * java.util.Map, java.util.Map)
	 */
	@Override
	@Transactional(readOnly = false)
	public Orders createOrderWithPay(CartOrders cart, Map<String, String> addonInfo, Map<String, String> payment)
			throws CoreException {
		String couponItem = addonInfo.get("coupon");
		String domain = addonInfo.get("domain");
		String couponProductId = "";
		String couponCartOrderProductId = "";
		String channelChild = addonInfo.get("channelChild");
		String remoteAddr = StringUtils.defaultString(addonInfo.get("remoteAddr"), "0.0.0.0");
		// String promoteProductId = StringUtils.defaultString(addonInfo.get("promoteProduct"), "");
		String storeId = addonInfo.get("storeId");// 达芙妮店代
		String tuangouId = addonInfo.get("tuangouId");// 团购编号
		String tuangouName = addonInfo.get("tuangouName");// 团购名称
		Member member = memberService.get(cart.getMemberId());
		if (member != null) {
			domain = member.getDomainSrc();
		}

		String paymentType = payment.get("paymentType");
		if (StringUtils.isBlank(paymentType)) {
			throw new CoreException("errors.payment.type.null");
		}
		BigDecimal chkVrtBlnc = new BigDecimal(StringUtils.defaultString(payment.get("vrtBlnc"), "0.0")).setScale(1);
		BigDecimal chkGiftCard = new BigDecimal(StringUtils.defaultString(payment.get("giftCard"), "0.0")).setScale(1);
		BigDecimal editBonus = new BigDecimal(StringUtils.defaultString(payment.get("bonus"), "0.0")).setScale(1);
		BigDecimal editShipFare = new BigDecimal(StringUtils.defaultString(payment.get("editShipFare"), "0.0")).setScale(1);
		Date currentDate = DateUtil.getCurrentTime();

		// check bonus
		checkBonus(cart, editBonus, domain, channelChild, member.getBalance());

		BigDecimal cpFaceValue = BigDecimal.ZERO;
		String cpItemUUID = "";
		String cpUUID = "";
		CouponItem couponItemObj = null;
		String[] dealCoupon = null;
		String[] processCoupon = null;
		BigDecimal bcCoupon = BigDecimal.ZERO;
		StringBuffer selectedCoupon = new StringBuffer();
		boolean duplCouponProduct = false;
		if (StringUtils.isNotBlank(couponItem)) {
			dealCoupon = couponItem.split(";");
		}

		// 建立訂單, 資料複製交由建構處理
		// Orders order = new Orders(cart);
		Map<String, Orders> joinOrders = new HashMap();
		for (String s : cart.getJoinOrderSupplySet()) {
			Orders order = new Orders(cart);
			joinOrders.put(s, order);
			order.setPaymentTp(paymentType);
			order.setDomainSrc(domain);
			order.setChannel_child(channelChild);
			order.setClientIp(remoteAddr);
			// 写入团购资讯
			if (StringUtils.isNotBlank(tuangouId) && StringUtils.isNotBlank(tuangouName)) {
				order.setTuangouId(Long.parseLong(tuangouId));
				order.setTuangouName(tuangouName);
			}
		}
		// 付款期限：線上支付: 24hr; 匯款/ATM/郵區 : 7x24 hr
		if ("10".equals(paymentType) || "20".equals(paymentType) || "30".equals(paymentType) || "60".equals(paymentType)) {
			Date dead7 = DateUtil.getTodayAddDays(7).getTime();
			if (DateUtil.checkDateBetween(currentDate, DateUtil.convertStringToDate("yyyyMMddHHmmss", "20110201000000"),
					DateUtil.convertStringToDate("yyyyMMddHHmmss", "20110209235959"), true, true)
					&& ("10".equals(paymentType) || "20".equals(paymentType))) {
				dead7 = DateUtil.getTodayAddDays(14).getTime();
			}

			dead7 = DateUtil.getLastTimestamp(Calendar.HOUR_OF_DAY, dead7);
			for (Orders o : joinOrders.values()) {
				o.setDeadline(dead7);
			}
		} else {
			Date dead1 = DateUtil.getTodayAddDays(1).getTime();
			dead1 = DateUtil.getLastTimestamp(Calendar.HOUR_OF_DAY, dead1);
			for (Orders o : joinOrders.values()) {
				o.setDeadline(dead1);
			}
		}
		// 建構時預設值
		// // 倉位資訊
		// order.setFromCity(" ");// 未來開放不同倉位時需記錄出倉位罝
		// order.setFromDistrict(" ");// 未來開放不同倉位時需記錄出倉位罝
		// order.setFromProvince(" ");// 未來開放不同倉位時需記錄出倉位罝
		// order.setPaymentSrc(" ");// 支付的厂商,

		int detailSeq = 1;
		for (Orders order : joinOrders.values()) {
			for (ApplyCampaign ac : cart.getApplyCampaign().values()) {
				order.getApplyCampaigns().add(new com.yaodian100.ec.order.entity.ApplyCampaign(order, ac));
			}
		}
		Set<String> scmSet = new HashSet();
		Set<String> supplySet = new HashSet();
		String getAddCmpPd = "";
		BigDecimal getTotalPriceSubDiscount = BigDecimal.ZERO;
		Map<String, String> prodCanUseCodMap = deliveryRuleService.cartDetailCanUseCodMap(cart.getCartId());
		Product p = null;
		Map<Long, String> prodReturnRuleMap = new HashMap<Long, String>();
		for (CartOrderProduct cartOrderProd : cart.getCartOrderProducts()) {
			if (cartOrderProd.getQty() <= 0) {
				// throw new CoreException("商品数量不可为 0", cartOrderProd.getProdId(), cartOrderProd.getProdSpecId());
				continue;
			}

			OrderProduct entityProd = new OrderProduct(cartOrderProd);
			if ("Y".equals(cartOrderProd.getIsScm())) {
				joinOrders.get(cartOrderProd.getSupplierId()).addProduct(entityProd);
			} else {
				joinOrders.get("N").addProduct(entityProd);
			}

			if (StringUtils.isNotBlank(cartOrderProd.getIsScm())) {
				scmSet.add(cartOrderProd.getIsScm());
			}
			if ("Y".equals(cartOrderProd.getIsScm())) {
				supplySet.add(cartOrderProd.getSupplierId());
			}
			if (null != dealCoupon) {
				if (dealCoupon.length > 0) {
					for (int icp = 0; icp < dealCoupon.length; icp++) {
						duplCouponProduct = false;
						processCoupon = dealCoupon[icp].split(",");
						couponCartOrderProductId = processCoupon[6].toString();
						if ("1".equals(couponCartOrderProductId)) {// 如果是1表示立即購買，用productId比對，如果是購物車就拿cartOrderProductId去比對
							couponCartOrderProductId = processCoupon[0].toString();
						}
						if (couponCartOrderProductId.equals(processCoupon[6].toString().equals("1") ? cartOrderProd.getProdId()
								: ObjectUtils.toString(cartOrderProd.getCartOrderProdId()))
								&& duplCouponProduct == false) {
							// bts
							couponItemObj = couponService.getItem(processCoupon[3].toString());
							if (couponItemObj == null) {
								logger.error("coupon 不存在,cart:" + cart + ",coupon item:" + processCoupon[3].toString());
								throw new CoreException("errors.coupon.item.null");
							}
							if (entityProd.getTotalPrice().compareTo(cpFaceValue) < 0) {
								cpFaceValue = entityProd.getTotalPrice();
							} else {
								cpFaceValue = couponItemObj.getCoupon().getFaceValue();
							}
							entityProd.setCoupon(cpFaceValue);
							bcCoupon = bcCoupon.add(cpFaceValue);
							selectedCoupon = selectedCoupon.append(couponItemObj.getUuid()).append(",");
							cpUUID = couponItemObj.getCoupon().getUuid();

							entityProd.setCouponId(cpUUID);
							// entityProd.setCouponItemId(couponItem);
							entityProd.setCouponItemId(processCoupon[3].toString());
							if (couponItemObj != null
									&& couponItemObj.getCoupon().getMinimumProductPrice().compareTo(entityProd.getTotalPrice()) == 1) {
								logger.error("Coupon 最小金額限制不符, cart prod:{}, coupon item:{}",
										new Object[] { entityProd, couponItemObj });
								throw new CoreException(CouponService.ERROR_COUPON_INACTIVE);
							}
							if (couponItemObj != null && !couponService.isValid(couponItemObj, entityProd)) {
								logger.error("Coupon 使用限制不符, cart prod:{}, coupon item:{}", new Object[] { entityProd, couponItemObj });
								throw new CoreException(CouponService.ERROR_COUPON_INACTIVE);
							}
						}
					}
					cpItemUUID = selectedCoupon.toString();
					// logger.error("xxxcpItemUUID:{}", cpItemUUID);
					duplCouponProduct = true;
				}
			}
			// 退換貨條件
			p = productService.get(cartOrderProd.getProdId());
			if (null != p) {
				if (StringUtils.isNotBlank(p.getReturnRule())) {
					entityProd.setReturnRule(p.getReturnRule());
				}
			}
			prodReturnRuleMap.put(entityProd.getOrderProdId(), entityProd.getReturnRule());

			BigDecimal prodWeight = BigDecimal.ZERO;
			for (CartOrderProductDetail cartOrderProductDetail : cartOrderProd.getDetails()) {
				if (cartOrderProductDetail.getQty() <= 0) {
					continue;
				}
				prodWeight = prodWeight.add(cartOrderProductDetail.getWeight().multiply(
						new BigDecimal(cartOrderProductDetail.getQty())));
				OrderProductDetail entityDetail = new OrderProductDetail(cartOrderProductDetail);
				if (null == prodCanUseCodMap.get(entityDetail.getProdId())
						|| StringUtils.isBlank(prodCanUseCodMap.get(entityDetail.getProdId()))) {
					entityDetail.setCanUseCod("Y");
				} else {
					entityDetail.setCanUseCod(prodCanUseCodMap.get(entityDetail.getProdId()).split(",")[1]);
				}
				if (entityDetail.getDetailTp().equals("5")) {
					getAddCmpPd = "Y";
				}
				// 預購商品要寫入預計出貨日
				Product detailProd = productService.get(entityDetail.getProdId());
				if (detailProd.getProductType() == 1 && null != detailProd.getExpectShipDate()) {
					entityDetail.setExpectShipDate(EcConstant.PATTERN_DATE_FORMAT.format(detailProd.getExpectShipDate()));
				}
				if (detailProd.getProductType() != 1) {
					// BO/订制商品供备货时间
					// 轉單商品
					SupplierApply sp = supplierApplyService.get(detailProd.getSupplierId());
					if (StringUtils.equals(detailProd.getIsScm(), "Y")) {
						// 有訂制天數
						if (StringUtils.equals(detailProd.getUseDeliveryDay(), "Y")) {
							entityDetail.setDeliveryDay(detailProd.getDeliveryDay());
						}
					}
					// BO商品
					if (StringUtils.equals(detailProd.getIsScm(), "B")) {
						// 有訂制天數
						if (StringUtils.equals(detailProd.getUseDeliveryDay(), "Y")) {
							entityDetail.setDeliveryDay(detailProd.getDeliveryDay());
						} else {
							if (null != sp && null != sp.getBoToWHDate()) {
								entityDetail.setBoToWhDate(sp.getBoToWHDate());
							}
						}
					}
				}
				// 業績報表規則
				if (entityDetail.getEcCost().intValue() == 0) {
					Product ptEcCost = productService.get(cartOrderProductDetail.getProdId());
					if (ptEcCost.getProductCost() != null) {
						entityDetail.setEcCost(ptEcCost.getProductCost());
					}
				}
				Shelf shelf = shelfService.getActiveShelfByProductId(cartOrderProductDetail.getProdId());
				if (null != shelf) {
					entityDetail.setGiveBonus(shelf.getGiveBonus());
				} else {
					entityDetail.setGiveBonus(0);
				}
				entityDetail.setDetailSeq(detailSeq);
				// 退換貨條件
				String detailReturnRule = MapUtils.getString(prodReturnRuleMap, entityDetail.getOrderProdId());
				if (StringUtils.isNotBlank(detailReturnRule)) {
					entityDetail.setReturnRule(detailReturnRule);
				}
				// 商品路径

				// 安得商品寫入訂製天數=4
				List<String> products = new ArrayList<String>();
				products.add(entityDetail.getProdId());
				if (this.andeProductService.hasAndeProduct(products)) {
					entityDetail.setBoToWhDate(4);
				}

				entityProd.addDetail(entityDetail);
				detailSeq++;
			}
			if (entityProd.getOrderProductDetail().isEmpty()) {
				logger.error("购物车 cart detail 为空, cart:" + cart + ",prod:" + cartOrderProd);
				throw new CoreException("errors.order.detail.empty");
			}

			Orders order = null;
			if ("Y".equals(cartOrderProd.getIsScm())) {
				order = joinOrders.get(cartOrderProd.getSupplierId());
			} else {
				order = joinOrders.get("N");
			}
			order.setCoupon(order.getCoupon().add(entityProd.getCoupon()));
			order.setAmount(order.getAmount().add(entityProd.getAmount()));
			order.setTotalPrice(order.getTotalPrice().add(entityProd.getTotalPrice()));
			order.setDiscount(order.getDiscount().add(entityProd.getDiscount()));
			order.setTotalWeight(order.getTotalWeight().add(prodWeight));

			if (entityProd.getAmount().intValue() < 0) {
				logger.error("訂單金額警示:" + joinOrders + "," + entityProd.getProdId() + "," + entityProd.getAmount());
			}
		}

		// 订单资料准备完毕, 计算运费
		BigDecimal shipfare = BigDecimal.ZERO;
		if (StringUtils.isNotBlank(storeId)) {
			if (joinOrders.size() > 1) {
				logger.error("達芙妮門店取貨无拆单逻辑, cart:" + cart);
				throw new CoreException("errors.order.dpn.split");
			}
			for (Orders o : joinOrders.values()) {
				o.setReceiverTp("30");// 表示達芙妮門店取貨
			}

			CommonCriteria crit = new CommonCriteria();
			crit.addEq("storeId", storeId);
			List<DPNStore> dpnstores = dpnService.getDPNStoretList(crit);
			if (dpnstores.size() > 0) {
				DPNStore dpnstore = dpnstores.get(0);
				StringBuffer rightDpnAdd = new StringBuffer();
				rightDpnAdd.append(dpnstore.getStoreAddress()).append("(").append(dpnstore.getStoreName()).append("-").append(
						dpnstore.getStoreType()).append(")");

				for (Orders order : joinOrders.values()) {
					order.setReceiverZip(dpnstore.getStoreZip());
					order.setReceiverAddr(rightDpnAdd.toString());
					order.setReceiverProvince("上海");
					order.setReceiverCity(dpnstore.getStoreCity());
					order.setReceiverArea(dpnstore.getStoreArea());
					order.setStoreId(storeId.trim());
				}
				if (null == tuangouId) {// 团购订单免运
					shipfare = addressService.getDaphneFee();
				}
			} else {
				// 若 storeId 不正确, 抛出错误讯息
				logger.error("达芙妮门店取货 storeId 错误, storeId:" + storeId + ",cart:" + cart + ",member:" + member);
				throw new CoreException("errors.order.receivertp.dpnstore", storeId);
			}
		} else {
			if (null == tuangouId) {// 团购订单免运
				shipfare = addressService.getFreight(cart.getReceiverProvince(), cart.getWeightSum().multiply(
						BigDecimal.valueOf(1000)), cart.getAmount().add(cart.getDiscount()), cart.getDiscount());
			}
			for (Orders order : joinOrders.values()) {
				order.setReceiverTp("10");
				order.setStoreId("");
			}
		}

		BigDecimal codFee = BigDecimal.ZERO;
		if ("30".equals(paymentType) || "60".equals(paymentType)) {
			codFee = addressService.getCodFee();
		}
		int count = joinOrders.size();
		BigDecimal avgShipfare = shipfare.divide(new BigDecimal(joinOrders.size()), RoundingMode.DOWN).setScale(1);
		BigDecimal avgCodFee = codFee.divide(new BigDecimal(joinOrders.size()), RoundingMode.DOWN).setScale(1);
		// 原始使用账户余额与礼品卡金额
		BigDecimal oldVrtBlnc = new BigDecimal(StringUtils.defaultString(payment.get("vrtBlnc"), "0.0")).setScale(1);
		BigDecimal oldGiftCard = new BigDecimal(StringUtils.defaultString(payment.get("giftCard"), "0.0")).setScale(1);
		BigDecimal oldBonus = new BigDecimal(StringUtils.defaultString(payment.get("bonus"), "0.0")).setScale(0);
		BigDecimal oldPay = cart.getAmount().subtract(oldBonus).subtract(bcCoupon);
		// 商品總額-discount-coupon+shipfare+codfee-virtualBalance-giftcardBalance-bonus
		BigDecimal oldMustPay = oldPay.subtract(oldVrtBlnc).subtract(oldGiftCard).add(shipfare).add(codFee); // 拆单前订单应付金额
		BigDecimal chkMustPay = oldMustPay;
		BigDecimal orderPay = BigDecimal.ZERO;

		BigDecimal remainderShipfare = BigDecimal.ZERO;
		BigDecimal remainderCodFee = BigDecimal.ZERO;
		BigDecimal remainderMustPay = BigDecimal.ZERO;
		BigDecimal remainderGiftcardBalance = BigDecimal.ZERO;
		BigDecimal remainderMywallet = BigDecimal.ZERO;
		BigDecimal remainderBonus = BigDecimal.ZERO;

		BigDecimal _bonus = BigDecimal.ZERO;
		BigDecimal _shipfare = BigDecimal.ZERO;
		BigDecimal _codfee = BigDecimal.ZERO;
		BigDecimal _giftcard = BigDecimal.ZERO;
		BigDecimal _myWallet = BigDecimal.ZERO;
		BigDecimal _mustPay = BigDecimal.ZERO;
		Campaign bc = null;
		BigDecimal perc = BigDecimal.ZERO;
		if (null == tuangouId) {
			// 会员积分檢查,团 购订单不送积分
			bc = campaignService.getActiveBonusCampaignByM02(addonInfo);
			perc = new BigDecimal(bc.getOffsetUpperLimit()).divide(BigDecimal.valueOf(100));
		}

		// 有拆单时，将订单金额由小到大排序
		if (joinOrders.size() > 1) {
			joinOrders = sortOrderByValue(joinOrders);
		}
		for (Orders order : joinOrders.values()) {
			// TODO_jeffma 平均运费
			if (count != 1) {
				_shipfare = avgShipfare;
				remainderShipfare = remainderShipfare.add(_shipfare);
				if (remainderShipfare.compareTo(shipfare) == 1) {
					remainderShipfare = remainderShipfare.subtract(shipfare);
					_shipfare = shipfare.subtract(remainderShipfare);
					remainderShipfare = shipfare;
				}
				order.setShipfare(_shipfare);

				_codfee = avgCodFee;
				remainderCodFee = remainderCodFee.add(_codfee);
				if (remainderCodFee.compareTo(codFee) == 1) {
					remainderCodFee = remainderCodFee.subtract(codFee);
					_codfee = codFee.subtract(remainderCodFee);
					remainderCodFee = codFee;
				}
				order.setCodFee(_codfee);

				// bonus照金额比例,myWallet、giftcardBalance用減的計算, 以免 order.mustPay 为负
				// 计算bonus(因在做訂單拆分時，如果採用與cart2一樣無條件進位的方式，很有可能導致最後一單是<0的情況，所以拆單時改用無條件捨去來做)
				// 积分检核方式为：订单商品金额-折扣来计算，所以在拆分时也是依这个规则计算

				if (oldBonus.compareTo(BigDecimal.ZERO) == 1 && null == tuangouId) {
					_bonus = oldBonus.multiply(order.getTotalPrice().subtract(order.getDiscount())).divide(cart.getAmount(), 0,
							RoundingMode.DOWN);

					// 订单金额折抵上限
					BigDecimal iOffset = order.getAmount().multiply(perc).setScale(0, RoundingMode.UP);

					// 订单折抵上限>可用的积分
					if (iOffset.compareTo(_bonus) == 1) {
						iOffset = _bonus;
					}
					// 订单最多可折抵积分
					if (iOffset.compareTo(new BigDecimal(bc.getOffsetDiscountLimit())) == 1) {
						iOffset = new BigDecimal(bc.getOffsetDiscountLimit());
					}

					remainderBonus = remainderBonus.add(iOffset);
					if (remainderBonus.compareTo(editBonus) == 1) {
						remainderBonus = remainderBonus.subtract(iOffset);
						iOffset = editBonus.subtract(remainderBonus);
						remainderBonus = editBonus;
					}
					order.setBonus(iOffset);
				} else {
					order.setBonus(BigDecimal.ZERO);
				}
				orderPay = order.getAmount().subtract(order.getBonus());

				// 以最後要付款的金額來決定禮品卡&帳戶餘額的計算比例
				if (oldMustPay.compareTo(BigDecimal.ZERO) == 1) {
					if (oldVrtBlnc.compareTo(BigDecimal.ZERO) == 0 && oldGiftCard.compareTo(BigDecimal.ZERO) == 0) {
						_mustPay = order.getAmount().subtract(order.getBonus()).subtract(order.getBenefit()).add(_shipfare).add(
								_codfee).add(order.getInstallmentFee()).setScale(1, RoundingMode.DOWN);
					} else {
						_mustPay = oldMustPay.multiply(orderPay).divide(oldPay, 1, RoundingMode.DOWN);
					}
					remainderMustPay = remainderMustPay.add(_mustPay);
					if (remainderMustPay.compareTo(chkMustPay) == 1) {
						remainderMustPay = remainderMustPay.subtract(_mustPay);
						_mustPay = chkMustPay.subtract(remainderMustPay);
						remainderMustPay = chkMustPay;
					}
					order.setMustPay(_mustPay);
				}
				if (oldVrtBlnc.compareTo(BigDecimal.ZERO) == 1 && oldGiftCard.compareTo(BigDecimal.ZERO) == 0) {// 使用账户余额支付,不使用礼品卡
					_myWallet = order.getAmount().add(_shipfare).add(_codfee).subtract(order.getBonus()).subtract(
							order.getBenefit()).subtract(order.getMustPay()).add(order.getInstallmentFee()).setScale(1,
							RoundingMode.DOWN);
					remainderMywallet = remainderMywallet.add(_myWallet);
					if (remainderMywallet.compareTo(chkVrtBlnc) == 1) {
						remainderMywallet = remainderMywallet.subtract(_myWallet);
						_myWallet = chkVrtBlnc.subtract(remainderMywallet);
						remainderMywallet = chkVrtBlnc;
					}
					order.setMyWallet(_myWallet);
				}
				if (oldGiftCard.compareTo(BigDecimal.ZERO) == 1 && oldVrtBlnc.compareTo(BigDecimal.ZERO) == 0) {// 使用礼品卡支付,不使用账户余额
					_giftcard = order.getAmount().add(_shipfare).add(_codfee).subtract(order.getBonus()).subtract(
							order.getBenefit()).subtract(order.getMustPay()).add(order.getInstallmentFee()).setScale(1,
							RoundingMode.DOWN);
					remainderGiftcardBalance = remainderGiftcardBalance.add(_giftcard);
					if (remainderGiftcardBalance.compareTo(chkGiftCard) == 1) {
						remainderGiftcardBalance = remainderGiftcardBalance.subtract(_giftcard);
						_giftcard = chkGiftCard.subtract(remainderGiftcardBalance);
						remainderGiftcardBalance = chkGiftCard;
					}
					order.setGiftcardBalance(_giftcard);
				}
				if (oldGiftCard.compareTo(BigDecimal.ZERO) == 1 && oldVrtBlnc.compareTo(BigDecimal.ZERO) == 1) {// 使用礼品卡支付&账户余额
					_myWallet = oldVrtBlnc.multiply(orderPay).divide(oldPay, 1, RoundingMode.DOWN);
					remainderMywallet = remainderMywallet.add(_myWallet);
					if (remainderMywallet.compareTo(chkVrtBlnc) == 1) {
						remainderMywallet = remainderMywallet.subtract(_myWallet);
						_myWallet = chkVrtBlnc.subtract(remainderMywallet);
						remainderMywallet = chkVrtBlnc;
					}
					order.setMyWallet(_myWallet);
					_giftcard = order.getAmount().add(_shipfare).add(_codfee).subtract(order.getMustPay()).subtract(
							order.getMyWallet()).subtract(order.getBonus()).subtract(order.getBenefit()).add(
							order.getInstallmentFee());
					remainderGiftcardBalance = remainderGiftcardBalance.add(_giftcard);
					if (remainderGiftcardBalance.compareTo(chkGiftCard) == 1) {
						remainderGiftcardBalance = remainderGiftcardBalance.subtract(_giftcard);
						_giftcard = chkGiftCard.subtract(remainderGiftcardBalance);
						remainderGiftcardBalance = chkGiftCard;
					}
					order.setGiftcardBalance(_giftcard);
				}
			} else {
				// count == 1 表示最后一笔. 放入余额
				order.setShipfare(shipfare.subtract(remainderShipfare));
				order.setMyWallet(chkVrtBlnc.subtract(remainderMywallet));
				order.setGiftcardBalance(chkGiftCard.subtract(remainderGiftcardBalance));
				order.setBonus(editBonus.subtract(remainderBonus));
				order.setCodFee(codFee.subtract(remainderCodFee));
				order.setMustPay(chkMustPay.subtract(remainderMustPay));
			}
			if (order.getBonus().compareTo(BigDecimal.ZERO) < 0) {
				throw new CoreException("Bonus不可为零", cart.getCartId());
			}
			count--;
		}

		// 订单应付金额为 amount(totalPrice-discount-coupon)+shipfare-bonus-benefit(?)-myWallet
		BigDecimal joinMustPay = BigDecimal.ZERO;
		for (Orders order : joinOrders.values()) {
			order.setMustPay(order.getAmount().add(order.getShipfare()).add(order.getCodFee()).subtract(order.getBonus())
					.subtract(order.getBenefit()).subtract(order.getMyWallet()).subtract(order.getGiftcardBalance()).add(
							order.getInstallmentFee()));
			joinMustPay = joinMustPay.add(order.getMustPay());
			if (!checkAmountBeforeOrder(order)) {// 检查订单金额不得为负项
				throw new CoreException("errors.order.amount.zero", cart.getCartId());
			}
		}

		// 转单商品加入购物车合并结帐
		for (Orders order : joinOrders.values()) {
			order.setJoinMustPay(joinMustPay);
		}

		/*
		 * OrderSt=00規則 1：貨到付款;2：首次未有交易成功;3：訂購金額為500元以上
		 */
		if ("30".equals(paymentType) || "60".equals(paymentType)) {// 貨到付款(30)
			// if (order.getMustPay().intValue() > 200) {
			// order.setOrderSt("00");// 00 訂單審核中-->20101025规则修订为200以上进审核中
			// } else {
			// 首购 cod 200元以下订单也需要审核,首购的订义: 1.365天内, 2.该会员 3.交易完成的订单 ==0 表示为首购
			// 大於 200 以上 且 首購

			for (Orders order : joinOrders.values()) {
				if (verifyOrder("365", member.getMemberId(), "90") && joinMustPay.intValue() > 200
						&& "off".equals(ServerValue.getBlockOrderPaymentType())) {
					order.setOrderSt("00");
				} else {
					order.setOrderSt("20");// 20 等待配貨
					order.setSyncDt(currentDate);// 同步用
				}
			}

			// }
		} else {
			if ("40".equals(paymentType) && joinMustPay.intValue() == 0) {
				for (Orders order : joinOrders.values()) {
					order.setOrderSt("20");// 20 等待配貨
				}
			} else {
				for (Orders order : joinOrders.values()) {
					order.setOrderSt("10");// 10 訂單成立
					if (order.getMyWallet().compareTo(BigDecimal.ZERO) == 1) {
						order.setPaymentDt(currentDate);
					}
				}
			}
		}

		for (Orders order : joinOrders.values()) {
			if ("40".equals(paymentType) && joinMustPay.intValue() == 0) {
				order.setPaymentSt("10");// 10完成付款
				order.setPaymentDt(currentDate);
				order.setSyncDt(currentDate);// 同步用
			} else {
				order.setPaymentSt("00");// 00等待付款
			}

			// 全部用账户余额付清，订单直接后送
			if ("40".equals(order.getPaymentTp())) {
				order.setSyncDt(currentDate);
			}
		}

		// 抓取滿額額設定值
		if (StringUtils.isNotBlank(getAddCmpPd)) {
			try {
				AddPurchaseSetting addPurchaseSetting = addPurchaseSettingService.getCurrentAddPurchaseSetting();
				for (Orders order : joinOrders.values()) {
					order.setCampProductLimit(addPurchaseSetting.getBasePrice());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			for (Orders order : joinOrders.values()) {
				order.setCampProductLimit(BigDecimal.ZERO);
			}
		}
		SupplierApply sp = null;
		for (String s : joinOrders.keySet()) {
			if ("N".equals(s)) {
				joinOrders.get("N").setOrderType("1");
			} else {
				joinOrders.get(s).setScmSupplierId(s);
				joinOrders.get(s).setOrderType("2");
				sp = supplierApplyService.get(s);
				if (null != sp) {
					joinOrders.get(s).setIsSelfShip(sp.getIsSelfShip());
				}
			}
		}

		// QQ返利網與返利網信任登入, 使用结帐页填写之 email, 并更新到 member profile
		if ("xx".equals(member.getSendEmail())) {
			member.setEmail(cart.getReceiverEmail());
			memberService.update(member);
			for (Orders order : joinOrders.values()) {
				order.setReceiverEmail(cart.getReceiverEmail());
				if (StringUtils.isBlank(order.getReceiverEmail())) {
					order.setReceiverEmail(member.getSendEmail());
				}
			}
		}
		// logger.info("O_member.getSendEmail():{}", member.getSendEmail());
		// logger.info("O_cart.getReceiverEmail():{}", cart.getReceiverEmail());

		String version = deliveryRuleService.findAddressVersion();
		List<String> joinOrderId = new ArrayList();
		String logisticProviderTp = ORDER_LOGISTIC_PROVIDER_TP.DEFAULT_PROVIDER.getValue();
		// 订单毛利率
		systemValueMenu = menuService.get("SystemValue");
		String fwEnable = systemValueMenu.getOptions().get("fw_enable").getMemo1();
		boolean fwResult = false;
		Float grossProfitRate = 0f;
		String exceptionCouponId = "";
		String mailBody = "";
		int exceptionCouponCount = 0;
		// logger.info("systemValueMenu.option:{}", systemValueMenu.getOptions());
		for (Orders order : joinOrders.values()) {
			// 若省的資料，若資料內有的省時，將省字移除
			if (order.getReceiverProvince().indexOf("省") > 0) {
				order.setReceiverProvince(order.getReceiverProvince().replace("省", ""));
			}
			order.setVersion(version);

			// 惡意訂單
			String badOrder = "";
			try {
				badOrder = validBadManOrder(order);
				if (!"true".equals(badOrder)) {
					order.setMemo(badOrder);
					// COD要审核
					if ("30".equals(paymentType) || "60".equals(paymentType)) {
						order.setOrderSt("00");
					} else {
						// 非COD付款期限30分钟
						Date dead30m = DateUtil.incrementMinutes(40).getTime();
						order.setDeadline(dead30m);
					}
				}
			} catch (Exception e1) {
				throw new CoreException("errors.order.badman", cart.getCartId());
			}
			// 限COD付款
			logisticProviderTp = deliveryRuleService.logisticProviderTp(prodCanUseCodMap);
			order.setLogisticProviderTp(logisticProviderTp);
			// 发票信息
			if ("02".equals(payment.get("invotype"))) {
				order.setInvoiceTp("02");// 02单位
				order.setInvoiceTitle(payment.get("invoTitle"));
			}
			save(order);

			joinOrderId.add(order.getOrderId());

			if (!"true".equals(badOrder)) {
				sendMail("order.badMan", "恶意订单通知", order);
			}

			if (false == validAddressDataNew(order)) {
				throw new CoreException("errors.order.address.not.match", cart.getCartId());
			}

			// 例外的礼券id不需检核毛利率
			exceptionCouponId = systemValueMenu.getOptions().get("exception_coupon_id").getMemo1();
			if (StringUtils.isNotBlank(exceptionCouponId)) {
				exceptionCouponCount = 0;
				for (OrderProduct op : order.getOrderProduct()) {
					if (StringUtils.isNotBlank(op.getCouponId())
							&& StringUtils.countMatches(exceptionCouponId, op.getCouponId()) > 0) {
						exceptionCouponCount = exceptionCouponCount + 1;
					}
				}
			}
			if (exceptionCouponCount == 0) {
				// 检查订单毛利率
				fwResult = validateOrderGrossProfitRate(systemValueMenu, cart, order);
				/*
				 * 启用防火墙(for前台, 前台購物車：creatId=memberId,createUser=null, 前台立即購買：cartId=uuid、createUser=memberId,
				 * 中台電話訂購：cartId=uuid、 createUser=中台loginUserName)
				 */
				if (fwResult) {
					grossProfitRate = Float.valueOf(systemValueMenu.getOptions().get("fw_lowest_gpm").getMemo1());
					Map<String, Object> contentMap = new HashMap<String, Object>();
					contentMap.put("order", order);
					CommonCriteria crit = new CommonCriteria();
					crit.addEq("orderId", order.getOrderId());
					List<OrderProductDetail> getOrderProdDetailList = getOrderProdDetailList(0, -1, crit,
							new String[] { "prodSeq asc" });
					contentMap.put("orderProducts", order.getOrderProduct());
					contentMap.put("orderdetails", getOrderProdDetailList);
					contentMap.put("basehref", "http://" + order.getDomainSrc());
					contentMap.put("totalCost", getOrderTotalCost(order));// 訂單成本
					contentMap.put("grossProfitRate", grossProfitRate);// 毛利率
					contentMap.put("shipfare", editShipFare);// 结帐页运费
					if (null != order.getApplyCampaigns() && order.getApplyCampaigns().size() > 0) {
						contentMap.put("applyCampaigns", order.getApplyCampaigns());
					}
					if (null == cart.getCreateUser() || cart.getMemberId().equals(cart.getCreateUser())) {
						contentMap.put("cartId", cart.getCartId());
					}
					String fwMail = systemValueMenu.getOptions().get("fw_mail").getMemo1();
					try {
						if (StringUtils.isNotBlank(fwMail)) {
							Mail mail = velocityService.formatToMail("order.grossProfitRateFail", contentMap);
							mail.setTo(fwMail);
							mail.setFrom(envParameters.getEmailFromSystem());
							mail.setBcc("feeling.wang@yaodian100.com");
							mailService.save(mail);
							mailBody = mail.getBody();
						}
					} catch (Exception e) {
						logger.error("订单防火墙通知信异常");
					}
				}
				if (fwResult && StringUtils.equalsIgnoreCase("on", fwEnable)
						&& (null == cart.getCreateUser() || cart.getMemberId().equals(cart.getCreateUser()))) {
					throw new CoreException("订单毛利率不符合＠" + mailBody);
				}
			}
		}

		for (Orders order : joinOrders.values()) {
			// 转单商品加入购物车合并结帐
			order.setJoinOrders(StringUtils.join(joinOrderId, ","));
		}

		// 訂單成立時增加記錄資訊:OS,Browser,cookies,request data
		// JSONObject.fromObject(requestMap).get("city")
		try {
			String userAgent = addonInfo.get("userAgent");
			userAgent = StringUtils.abbreviate(userAgent, 200);
			String bcookie = addonInfo.get("bcookie");
			if (null != addonInfo.get("requestMap")) {
				String requestMap = addonInfo.get("requestMap");
				OrderUserData orderUserData = new OrderUserData();
				orderUserData.setOrderId(joinOrders.values().iterator().next().getOrderId());
				orderUserData.setOsBrowser(userAgent);
				orderUserData.setRequestData(StringUtils.defaultString(requestMap));
				orderUserData.setUserCookies(bcookie);
				ordersUserDataDao.save(orderUserData);
			}
		} catch (Exception e) {
			logger.error("OrderUserData_exception:{}", e);
		}
		String tmpProdId = null;
		OrderCreditCardCampaign creditCardCampaign = null;
		OrderBonusCampaign obc = null;
		for (Orders order : joinOrders.values()) {
			for (Iterator<OrderProduct> iter = order.getOrderProduct().iterator(); iter.hasNext();) {
				OrderProduct orderProdEntity = iter.next();
				orderProdEntity.setOrderId(order.getOrderId());
				saveOrderProd(orderProdEntity);
				// 立即购买 cart.cartId != order.memberId (只检查主商品部份)
				if (!cart.getCartId().equals(order.getMemberId())
						&& Arrays.asList("0", "1", "6", "7").contains(orderProdEntity.getProdTp())) {
					tmpProdId = orderProdEntity.getProdId();
				}
				for (Iterator<OrderProductDetail> iterDetail = orderProdEntity.getOrderProductDetail().iterator(); iterDetail
						.hasNext();) {
					OrderProductDetail orderProdDetailEntity = iterDetail.next();
					orderProdDetailEntity.setOrderId(order.getOrderId());
					orderProdDetailEntity.setOrderProdId(orderProdEntity.getOrderProdId());
					saveOrderDetail(orderProdDetailEntity);
				}
			}

			// 信用卡支付-分期付款(立即購買/達芙尼到店取貨)
			if (StringUtils.equals("80", paymentType) && !cart.getCartId().equals(order.getMemberId())
					&& StringUtils.isNotBlank(tmpProdId) && null != cart.getCreditcardDetail()) {
				creditCardCampaign = new OrderCreditCardCampaign();
				creditCardCampaign.setCreditcardDetailId(cart.getCreditcardDetail().getId());
				creditCardCampaign.setCreditcardId(cart.getCreditcardDetail().getCreditcard().getId());
				creditCardCampaign.setCreditcartPercentage(cart.getCreditcardDetail().getPeriodFees().get(cart.getPeriod()));
				creditCardCampaign.setCreditcartPeriod(cart.getPeriod());
				creditCardCampaign.setOrderId(order.getOrderId());
				creditCardCampaign.setProductId(tmpProdId);
				orderCreditCardCampaignDao.save(creditCardCampaign);

				order.setInstallmentFee(order.getMustPay().multiply(
						new BigDecimal(creditCardCampaign.getCreditcartPercentage()).multiply(new BigDecimal(0.01))).setScale(1,
						RoundingMode.HALF_UP));
				order.setMustPay(order.getMustPay().add(order.getInstallmentFee()));
				order.setJoinMustPay(order.getJoinMustPay().add(order.getInstallmentFee()));
				update(order);
			}
			// 会员积分折抵比例/上限(记录),不论使用与否，都要写记录(才会发送积分),团购订单不发送订单成立积分
			if (null == order.getTuangouId() && null != bc) {
				obc = saveOrderBonusSetting(order, new BigDecimal(bc.getOffsetRate()),
						new BigDecimal(bc.getOffsetUpperLimit()), new BigDecimal(bc.getOffsetDiscountLimit()));
				order.setOrderBonusCampaign(obc);
			}
		}

		// 需支付的訂單:"10-银行滙款"20-邮局汇款"50-网上支付/第三方支付"70-信用卡：一次付清"80-信用卡：分期"
		if (Arrays.asList("10", "20", "50", "70", "80").contains(paymentType)) {
			memberService.updateOrder2PayBalance(cart.getMemberId());
		}

		// transferService.chargeByBonusTransfer(order);

		// 成立訂單後，刪除購物車，扣除帳戶餘額，扣除coupon，扣除bonus
		try {
			for (Orders order : joinOrders.values()) {
				logService.save(this.getClass().getName(), "createOrderWithPay", new Object[] { cart, order, addonInfo,
						payment, joinOrders });
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			if (duplCouponProduct != true) {
				cpItemUUID = null;
			}
			for (Orders order : joinOrders.values()) {
				order = calcOrderProduct(order);// 计算商品的礼品卡、账户余额、积分、运费、cod手续费、分期手续费、mustpay摊提费用比例
				update(order);
				afterOrders(order, order.getMyWallet(), cpItemUUID, order.getBonus(), order.getGiftcardBalance());
				if (null != order.getTuangouId()) {// 团购订单成立订单时订单数要+1
					ShelfTuangou shelfTuangou = (ShelfTuangou) baseMgr.get(ShelfTuangou.class, order.getTuangouId());
					if (null != shelfTuangou) {
						shelfTuangou.setOrderQty(shelfTuangou.getOrderQty() + 1);
					}
					baseMgr.saveOrUpdate(shelfTuangou);
				}
				if (null == order.getTuangouId()) {// 团购订单不发mail
					// 訂單成立發mail
					sendApplyClaimMail("orderDone", order);
				}
				// 付款完成發mail
				if (order.getOrderSt().equals("20") && order.getPaymentSt().equals("10")) {
					sendApplyClaimMail("order.gotMoney", order);
				}
			}

			// 刪除購物車
			if (cart.getCartId().equals(cart.getMemberId())) {// null表示為直接購買, createUser null
				// 表示電話訂購
				cartordersService.delete(cart);
			}
		} catch (CoreException ce) {
			ce.printStackTrace();
			throw new CoreException(ce.getMessage(), ce);
		} catch (Exception e) {
			e.printStackTrace();
			throw new CoreException(e.getMessage(), e);
		}
		return joinOrders.values().iterator().next();
	}

	private void createServiceOrder(Orders order, String description, int srcType, String reasonTp) {

		if (reasonTp == null) {
			reasonTp = " ";
		}
		Map<String, String> prodCanUseCodMap = deliveryRuleService.orderDetailCanUseCodMap(order.getOrderId());
		ServiceOrders serviceOrder = new ServiceOrders();

		BeanUtils.copyProperties(order, serviceOrder);
		serviceOrder.setReceiverEmail(order.getReceiverEmail());
		serviceOrder.setSrcType(srcType);
		serviceOrder.setAccessaryDescription("无");
		serviceOrder.setDescription(description);
		serviceOrder.setReason(description);
		serviceOrder.setReasonTp(reasonTp);
		Date createDate = new Date();
		serviceOrder.setCreateDate(createDate);
		serviceOrder.setCreateUser("SYSTEM");
		// Member member = null;
		// member = (Member) baseMgr.get(Member.class, order.getMemberId());
		serviceOrder.setLoginId(order.getLoginId());
		serviceOrder.setMemberId(order.getMemberId());
		serviceOrder.setMemberName(order.getMemberName());
		serviceOrder.setMemo(description);
		serviceOrder.setOrderSt("10");
		if (srcType == 3) {
			serviceOrder.setReturnSt("10");
		} else if (srcType == 4 || srcType == 7) {
			// 配送異常
			serviceOrder.setReturnSt("00");
		}
		serviceOrder.setModifyUser("SYSTEM");
		serviceOrder.setServiceDt(createDate);
		serviceOrder.setOrderId(order.getOrderId());
		serviceOrder.setClientIp("localhost");
		// 整张取消
		Collection<ServiceOrderProduct> serviceOrderProducts = new ArrayList<ServiceOrderProduct>();
		for (OrderProduct op : order.getOrderProduct()) {
			ServiceOrderProduct sop = new ServiceOrderProduct();
			BeanUtils.copyProperties(op, sop);
			sop.setServiceOrderDetail(new ArrayList<ServiceOrderDetail>());
			for (OrderProductDetail opd : op.getOrderProductDetail()) {
				ServiceOrderDetail sod = new ServiceOrderDetail();
				BeanUtils.copyProperties(opd, sod, IGNORE_PROPERTIES_WHEN_COPY_FROM_ORDER_DETAIL_TO_SERVICE_DETAIL);
				sod.setOrgDetailSeq(sod.getDetailSeq());
				sod.setOrgProdSpecId(sod.getProdSpecId());
				sod.setOrgProdSpecName(sod.getProdSpecName());
				if (srcType == 4 || srcType == 7) {
					sod.setOrgShippingLineOid(opd.getShippingLineOid());
					sod.setOrgShippingOid(opd.getShippingOid());
				}
				if (null == prodCanUseCodMap.get(sod.getProdId()) || StringUtils.isBlank(prodCanUseCodMap.get(sod.getProdId()))) {
					sod.setCanUseCod("Y");
				} else {
					sod.setCanUseCod(prodCanUseCodMap.get(sod.getProdId()).split(",")[1]);
				}
				sop.getServiceOrderDetail().add(sod);
			}
			serviceOrderProducts.add(sop);
		}

		// 針對達芙妮重發單
		if (srcType == 7) {
			serviceOrder.setReturnBenefit(new BigDecimal(0));
			serviceOrder.setReturnBonus(new BigDecimal(0));
			serviceOrder.setReturnCoupon(new BigDecimal(0));
			serviceOrder.setReturnCash(new BigDecimal(0));
			serviceOrder.setReturnMyWallet(order.getMyWallet());
			serviceOrder.setReturnShipfare(new BigDecimal(0));
			serviceOrder.setReturnCodFee(new BigDecimal(0));
			serviceOrder.setReturnGiftcardBalance(order.getGiftcardBalance());

			serviceOrder.setRealBenefit(new BigDecimal(0));
			serviceOrder.setRealBonus(new BigDecimal(0));
			serviceOrder.setRealCoupon(new BigDecimal(0));
			serviceOrder.setRealCash(new BigDecimal(0));
			serviceOrder.setRealMyWallet(new BigDecimal(0));
			serviceOrder.setRealShipfare(new BigDecimal(0));
			serviceOrder.setRealCodFee(new BigDecimal(0));
			serviceOrder.setReturnInstallmentFee(new BigDecimal(0));
			serviceOrder.setRealInstallmentFee(new BigDecimal(0));
			serviceOrder.setRealGiftcardBalance(new BigDecimal(0));

			serviceOrder.setReasonTp(order.getReceiverTp());
			serviceOrder.setStoreId(order.getStoreId());

		} else {
			// 201107.依照財務的要求，有退費時分期手續費將不被計算再realcash和returncash中
			BigDecimal realCash = order.getCash();
			BigDecimal returnCash = order.getCash();
			if (order.getCash().compareTo(BigDecimal.ZERO) > 0 && "80".equals(order.getPaymentTp())) {
				realCash = new BigDecimal(order.getCash().longValue() - order.getInstallmentFee().longValue());
				returnCash = new BigDecimal(order.getCash().longValue() - order.getInstallmentFee().longValue());
			}
			serviceOrder.setReturnBenefit(order.getBenefit());
			serviceOrder.setReturnBonus(order.getBonus());
			serviceOrder.setReturnCoupon(order.getCoupon());
			serviceOrder.setReturnCash(returnCash);
			serviceOrder.setReturnMyWallet(order.getMyWallet());
			serviceOrder.setReturnShipfare(order.getShipfare());
			serviceOrder.setReturnCodFee(order.getCodFee());
			serviceOrder.setReturnGiftcardBalance(order.getGiftcardBalance());

			serviceOrder.setRealBenefit(order.getBenefit());
			serviceOrder.setRealBonus(order.getBonus());
			serviceOrder.setRealCoupon(order.getCoupon());
			serviceOrder.setRealCash(realCash);
			serviceOrder.setRealMyWallet(order.getMyWallet());
			serviceOrder.setRealShipfare(order.getShipfare());
			serviceOrder.setRealCodFee(order.getCodFee());
			serviceOrder.setRealGiftcardBalance(order.getGiftcardBalance());

			// 退分期手續費，如果cash是0代表沒收錢，以order的部份來說有cash才有可能會產生installmentfee
			if (order.getCash().compareTo(BigDecimal.ZERO) > 0 && "80".equals(order.getPaymentTp())) {
				serviceOrder.setReturnInstallmentFee(order.getInstallmentFee());
				serviceOrder.setRealInstallmentFee(order.getInstallmentFee());
			} else {
				serviceOrder.setReturnInstallmentFee(BigDecimal.ZERO);
				serviceOrder.setRealInstallmentFee(BigDecimal.ZERO);
			}
		}
		// 限COD付款
		String logisticProviderTp = ORDER_LOGISTIC_PROVIDER_TP.DEFAULT_PROVIDER.getValue();
		logisticProviderTp = deliveryRuleService.logisticProviderTp(prodCanUseCodMap);
		serviceOrder.setLogisticProviderTp(logisticProviderTp);
		serviceOrder.setOrderType(order.getOrderType());
		serviceOrder.setScmSupplierId(order.getScmSupplierId());
		// 無論如何，是cod的單，取消都不應該有cash欄位值
		if (order.getPaymentTp().equals(Orders.ORDER_PAYMENT_TYPE.ARRIVE.getValue())) {
			serviceOrder.setReturnCash(new BigDecimal(0));
			serviceOrder.setRealCash(new BigDecimal(0));
		}
		try {

			serviceOrderService.saveServiceOrders(order, serviceOrder, serviceOrderProducts, true);

		} catch (CoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void createShipExceptionServiceOrder(Orders order, String description) {
		createServiceOrder(order, description, ServiceOrders.SERVICE_TYPE.SHIP_EXCEPTION.getValue(), " ");

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#getAllOrdersMemberId(int, int,
	 * com.yaodian100.core.common.dao.impl.CommonCriteria, java.lang.String[])
	 */
	@Override
	public List<String> getAllOrdersMemberId(int firstResult, int maxResults) throws CoreException {
		List<String> memberIds = getDao().getNameQuery("Orders.getAllOrdersMemberId", null, firstResult, maxResults);
		return memberIds;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#getAllOrdersMemberIdSize()
	 */
	@Override
	public long getAllOrdersMemberIdSize() throws CoreException {
		List<Long> size = getDao().getNameQuery("Orders.getAllOrdersMemberIdSize", null, 0, -1);
		return size.get(0).longValue();
	}

	@Override
	public List<String> getChannelList(String orderId) throws CoreException {
		Map<String, Object> attrs = new HashMap<String, Object>();
		StringBuilder sb = new StringBuilder("");

		sb.append("select p.prodId,sum(p.qty),sum(p.amount)/sum(p.qty), ");
		sb.append("p.categoryPath ,p.prodName, p.totalPrice, p.amount ");
		sb.append("from OrderProduct p ");
		sb.append("where 1 = 1 ");
		if (StringUtils.isNotBlank(orderId)) {
			sb.append("and p.orderId = :orderId ");
			attrs.put("orderId", orderId);
		}
		sb.append("group by p.prodId,p.categoryPath,p.prodName, p.totalPrice, p.amount ");

		List<String> orderDetailList = getDao().getQueryByMap(sb.toString(), attrs, 0, -1);
		return orderDetailList;
	}

	public EnvParameters getEnvParameters() {
		return envParameters;
	}

	public List<OrderProductDetail> getOrderProdDetailList(int firstResult, int maxResults, CommonCriteria criteria,
			String[] sortOrder) throws CoreException {
		String[] defaultSort = new String[] { "orderId", "prodSeq", "detailSeq asc" };
		List<OrderProductDetail> opds = new ArrayList<OrderProductDetail>();
		if (sortOrder == null) {
			opds = orderProductDetailDao.getListPageable(criteria, defaultSort, firstResult, maxResults);
		}
		opds = orderProductDetailDao.getListPageable(criteria, sortOrder, firstResult, maxResults);
		if (null != opds && opds.size() > 0) {
			Product product = null;
			try {
				for (OrderProductDetail opd : opds) {
					product = productService.get(opd.getProdId());
					opd.setCategoryPath(product.getCategory().getCategoryPath());
					opd.setCategoryName(categoryService.makeCategorieURL(product.getCategory().getId(), false).replaceAll("&gt;",
							">"));
				}
			} catch (Exception e) {
				logger.error("OrderProductDetail:categoryPath or categoryName is null...");
			}
		}
		return opds;
	}

	@Override
	public Orders getOrder(String orderId) {
		if (orderId == null) {
			return null;
		}
		Orders order = null;
		order = this.getDao().get(orderId);
		if (order.getBonus().compareTo(BigDecimal.ZERO) == 1) {
			order.setOrderBonusCampaign(orderBonusCampaignDao.get(orderId));
		}
		return order;
	}

	@Override
	public OrderProduct getOrderProduct(Long orderProductId) {
		if (orderProductId == null) {
			return null;
		}
		return this.orderProductDao.get(orderProductId);
	}

	@Override
	public OrderProductDetail getOrderProductDetail(Long orderDetailId) {
		if (orderDetailId == null) {
			return null;
		}
		return this.orderProductDetailDao.get(orderDetailId);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seecom.yaodian100.ec.order.service.OrderService#getOrderProdDetailListSize(com.yaodian100.core.common.dao.impl.
	 * CommonCriteria)
	 */
	public Number getOrderProdDetailListSize(CommonCriteria criteria) throws CoreException {
		return orderProductDetailDao.getListSize(criteria);
	}

	@Override
	public List<OrderProduct> getOrderProdList(int firstResult, int maxResults, CommonCriteria criteria,
			String[] sortOrder) throws CoreException {
		String[] defaultSort = new String[] { "orderId", "prodSeq" };
		if (sortOrder == null) {
			return orderProductDao.getListPageable(criteria, defaultSort, firstResult, maxResults);
		}
		return orderProductDao.getListPageable(criteria, sortOrder, firstResult, maxResults);
	}

	@Override
	public Collection<Orders> getOrdersByMemberId(String memberId) throws CoreException {
		if (null == memberId) {
			throw new CoreException("会员资料有误");
		}
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("memberId", memberId);
		return this.getList(0, -1, crit, null);
	}

	@Override
	public Orders getOrdersByOrderId(String orderId, String memberId) throws CoreException {
		if (StringUtils.isBlank(orderId)) {
			throw new CoreException("订单资料有误");
		}
		Orders order = this.get(orderId);
		if (!order.getMemberId().equals(memberId)) {
			throw new CoreException("订单资料有误");
		}
		return order;
	}

	@Override
	public List<OrderProductDetail> getOrderDetailListByOrderProdId(Long orderProdId) {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq("orderProdId", orderProdId);
		return this.orderProductDetailDao.getList(criteria, new String[] { "detailSeq" });
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#manualReturnShipfare(java.lang.String)
	 */
	@Override
	public void manualReturnShipfare(String orderId) {
		Orders order = (Orders) baseMgr.get(Orders.class, orderId);
		// ServiceOrders so=this.createServiceOrder(order, "运费溢收返还", ServiceOrders.SERVICE_TYPE.SHIP_EXCEPTION.getValue(),
		// ServiceOrders.REASON_TYPE.USER_RETURN_SHIPFARE.getValue());

	}

	@Override
	@Transactional(readOnly = false)
	public boolean refundToMyAccount() throws CoreException {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean returnApply(Long orderProdId, int qty) throws CoreException {
		OrderProduct orderProd = orderProductDao.get(orderProdId);
		// TODO Log 退货申请
		if (orderProd.getQty() - orderProd.getReturnQty() > qty) {
			throw new CoreException("退货数量大于可退数量，请重新输入退货数量");
		}
		orderProd.setReturnQty(qty + orderProd.getReturnQty());
		orderProd.setReturn(true);
		orderProductDao.update(orderProd);
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean returnCancel(Long orderProdId, int qty) throws CoreException {
		OrderProduct orderProd = orderProductDao.get(orderProdId);
		// TODO Log 退货取消
		if (orderProd.getReturnQty() < qty) {
			orderProd.setReturnQty(orderProd.getReturnQty() - qty);
		}
		orderProductDao.update(orderProd);
		return true;
	}

	@Transactional(readOnly = false)
	public void saveOrderDetail(OrderProductDetail orderProductDetail) throws CoreException {
		orderProductDetailDao.saveOrUpdate(orderProductDetail);
	}

	@Transactional(readOnly = false)
	public void saveOrderProd(OrderProduct orderProduct) throws CoreException {
		orderProductDao.saveOrUpdate(orderProduct);
	}

	@Override
	@Transactional(readOnly = false)
	public void sendApplyClaimMail(String velocityTemplate, Orders order) throws CoreException {

		// if (paymentTpMenu == null) {
		// paymentTpMenu = menuService.get("Order.PaymentTp");
		//
		// }
		try {
			Member member = memberService.get(order.getMemberId());

			// 已收到货款寄简讯
			if ("order.gotMoney".equals(velocityTemplate)) {

				if (member.getMobile() != null && member.getMobile().length() > 0) {
					float myWallet = order.getMyWallet() != null ? order.getMyWallet().floatValue() : 0;
					float giftcardBalance = order.getGiftcardBalance() != null ? order.getGiftcardBalance().floatValue() : 0;
					float mustPay = order.getMustPay() != null ? order.getMustPay().floatValue() : 0;
					float orderAmount = myWallet + giftcardBalance + mustPay;
					String msg = "您好，您在耀点100的订单" + order.getOrderId() + "已支付成功，商品将于近日送出，敬请查收！";
					smsService.sendSms(member.getMobile(), msg, order.getOrderId());
				}
			}

			Map<String, Object> contentMap = new HashMap<String, Object>();
			CommonCriteria commonCriteria = new CommonCriteria();
			commonCriteria.addEq("orderId", order.getOrderId());
			// logger.info("sendApplyClaimMail_orderId:", order.getOrderId());
			OrderProduct op = getOrderProdList(0, -1, commonCriteria, null).get(0);
			if (op.getProdTp().equals("1")) { // 预购商品
				contentMap.put("product", productService.get(op.getProdId()));
			} else {
				contentMap.put("product", null);
			}

			contentMap.put("order", order);
			contentMap.put("deadline", FastDateFormat.getInstance(EcConstant.PATTERN_TIMESTAMP).format(order.getDeadline()));
			contentMap.put("orderDt", FastDateFormat.getInstance(EcConstant.PATTERN_TIMESTAMP).format(order.getOrderDt()));
			CommonCriteria crit = new CommonCriteria();
			crit.addEq("orderId", order.getOrderId());
			List<OrderProductDetail> getOrderProdDetailList = getOrderProdDetailList(0, -1, crit,
					new String[] { "prodSeq asc" });
			contentMap.put("orderdetails", getOrderProdDetailList);
			contentMap.put("paymentTpMenu", paymentTpMenu);
			contentMap.put("customerFax", ServerValue.getCustomerFax());
			contentMap.put("customerTel", ServerValue.getCustomerTel());
			contentMap.put("contextpath", ServerValue.getFrontContextPath());
			contentMap.put("basehref", "http://" + order.getDomainSrc());

			if ("order.gotMoney".equals(velocityTemplate)) {
				List<MailBanner> mailBannerList = this.mailBannerService.getMailBannerByPosition("01");
				contentMap.put("mailBanners", mailBannerList);
			}

			Mail mail = velocityService.formatToMail(velocityTemplate, contentMap);
			mail.setTo(member.getSendEmail());
			mail.setFrom(envParameters.getEmailFromSystem());
			if (order.getOrderSt().equals("00")) {
				mail.setSubject("订单已提交，请等待客服人员与您确认货到付款发货事宜");
			}
			if ("orderDone".equals(velocityTemplate)) {
				mail.setSubject("您的订单" + order.getOrderId() + "已提交");
			}
			mailService.save(mail);
		} catch (Exception e) {
			logger.error("err:" + e.getMessage());
		}
	}

	@Override
	@Transactional(readOnly = false)
	public void sendMailForProductArrive(Orders order) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd");
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("order", order);
		contentMap.put("orderId", order.getOrderId());
		contentMap.put("orderDate", df.format(order.getCreateDate()));
		contentMap.put("memberName", order.getMemberName());
		contentMap.put("receiverAddr", order.getReceiverProvince() + "，" + order.getReceiverCity() + "，"
				+ order.getReceiverArea() + order.getReceiverAddr() + order.getReceiverZip());

		float mustPay = order.getMustPay() != null ? order.getMustPay().floatValue() : 0;
		float myWallet = order.getMyWallet() != null ? order.getMyWallet().floatValue() : 0;
		float orderAmount = mustPay + myWallet;
		String logisticNum = "";
		String logisticComp = "";
		List<String> logisticNums = new ArrayList<String>();
		contentMap.put("orderAmount", JspUtil.currency(orderAmount));
		contentMap.put("mustPay", JspUtil.currency(order.getMustPay()));
		contentMap.put("paymentType", JspUtil.menuOption("Order.PaymentTp", order.getPaymentTp()).getName());
		contentMap.put("receiverName", order.getReceiverName());
		for (OrderProduct op : order.getOrderProduct()) {
			if (op.getLogisticSendDt() != null) {
				contentMap.put("productSendDate", df2.format(op.getLogisticSendDt()));
			} else {// 當此值為空時，使用觸發當天的日期。
				contentMap.put("productSendDate", df2.format(new Date()));
			}
			if (StringUtils.isNotBlank(op.getLogisticRefNum()) && StringUtils.isNotBlank(op.getLogisticCompany())) {
				if (!logisticNums.contains(op.getLogisticRefNum())) {
					logisticNums.add(op.getLogisticRefNum());
					logisticNum += "，" + op.getLogisticRefNum();

					LogisticProvider lp = (LogisticProvider) baseMgr.get(LogisticProvider.class, op.getLogisticCompany());
					if (null != lp) {
						logisticComp += "，" + lp.getName();
					} else {
						logisticComp += "，" + op.getLogisticCompany();
					}
				}
			}
		}

		if (logisticNum.length() > 2) {
			logisticNum = logisticNum.substring(1);
		}
		if (logisticComp.length() > 2) {
			logisticComp = logisticComp.substring(1);
		}
		contentMap.put("logisticNum", logisticNum);
		contentMap.put("logisticComp", logisticComp);

		contentMap.put("contextPath", ServerValue.getFrontContextPath());
		contentMap.put("basehref", "http://" + order.getDomainSrc());
		contentMap.put("domainSrc", order.getDomainSrc());
		Mail mail = velocityService.formatToMail("order_product_arrive", contentMap);
		mail.setFrom(envParameters.getEmailFromSystem());
		mail.setTo(order.getReceiverEmail());

		mailService.save(mail);
	}

	public void setCartordersService(CartOrdersService cartordersService) {
		this.cartordersService = cartordersService;
	}

	public void setEnvParameters(EnvParameters envParameters) {
		this.envParameters = envParameters;
	}

	public void setMailService(MailService mailService) {
		this.mailService = mailService;
	}

	public void setMemberService(MemberService memberService) {
		this.memberService = memberService;
	}

	public void setMenuService(DomainService<Menu> menuService) {
		this.menuService = menuService;
	}

	public void setOrderProductDao(ObjectDao<OrderProduct> orderProductDao) {
		this.orderProductDao = orderProductDao;
	}

	public void setOrderProductDetailDao(ObjectDao<OrderProductDetail> orderProductDetailDao) {
		this.orderProductDetailDao = orderProductDetailDao;
	}

	public void setPaymentTpMenu(Menu paymentTpMenu) {
		this.paymentTpMenu = paymentTpMenu;
	}

	public void setTransferService(TransferService transferService) {
		this.transferService = transferService;
	}

	public void setVelocityService(TemplateService velocityService) {
		this.velocityService = velocityService;
	}

	@Override
	@Transactional(readOnly = false)
	public void syncOrder(Orders order) {
		if (!StringUtils.equalsIgnoreCase("Y", order.getExceptionFlag())) {// 异常订单不同步
			// 订单金额检核(有异常就写一笔memo，发mail, 并写入flag)
			checkOrderAmountFw(order);

			// 訂單配貨中
			// 訂單配貨中
			if (order.getOrderSt().equals("20")) {
				for (OrderProduct op : order.getOrderProduct()) {

					if (op.getProdTp().equals("6")) {
						List list = new ArrayList();
						// N選M
						for (OrderProductDetail opd : op.getOrderProductDetail()) {

							if (op.getProdSpecId().equals(opd.getProdSpecId())) {
								logger.debug("N pick M:avoid NM orderProduct's prodSpecId:" + op.getProdSpecId());

								list.add(opd);
							}
						}
						for (Object obj : list) {
							op.getOrderProductDetail().remove(obj);
						}

					}
				}
				order.setOrderSt("25");

				batchJobService.save(Orders.ORDER_BEAN.CREATE.getValue(), toXML(order), null, order.getOrderId());
				order.setSync(true);
				// 訂單同步時，若是付款方式COD／POS，需要寫入payment_dt
				if (order.getPaymentTp().equals(Orders.ORDER_PAYMENT_TYPE.ARRIVE.getValue())
						|| order.getPaymentTp().equals(Orders.ORDER_PAYMENT_TYPE.ARRIVE_CARD.getValue())) {
					order.setPaymentDt(new Date());
				}

				baseMgr.update(order);
				// 货到付款发送简讯
				if (order.getPaymentTp().equals(Orders.ORDER_PAYMENT_TYPE.ARRIVE.getValue())
						|| order.getPaymentTp().equals(Orders.ORDER_PAYMENT_TYPE.ARRIVE_CARD.getValue())) {
					if (order.getReceiverMobile() != null && order.getReceiverMobile().length() > 0) {
						String smsMsg = "您在耀点100货到付款订单" + order.getOrderId() + "已提交，我們将尽快确认与处理，请在收货时向送货员支付您的货款"
								+ JspUtil.currency(order.getMustPay()) + "元。";
						smsService.sendSms(order.getReceiverMobile(), smsMsg, order.getOrderId());
					}
				}

				// 使用者自行取消
			} else if (order.getOrderSt().equals("81")) {
				// 需建立取消單
				order.setSync(true);
				serviceOrderService.createCancelOrderForSyncOrder(order.getOrderId(), "已付款但取消订单", "已付款但取消订单", order
						.getMemberId(), order.getClientIp(), order.getB2eId());

			}
		}
	}

	private void toCapture(String memberId, String orderId) {
		Set<String> capFile = new HashSet();
		logger.debug("orderId: {}", orderId);
		Orders order = get(orderId);
		List<OrderProduct> orderProducts = order.getOrderProduct();

		Map objs = new HashMap();
		objs.put("sValue", ServerValue.getInstance());
		objs.put("memberObj", memberService.get(order.getMemberId()));
		objs.put("applySource", order.getChannel());
		for (OrderProduct op : orderProducts) {
			objs.put("oProd", op);
			String[] categoryArray = StringUtils.split(op.getCategoryPath(), "/");
			objs.put("z", categoryArray[categoryArray.length - 1]);
			logger.debug("order:{}, orderProduct:{}, detailSize:{}", new Object[] { op.getOrderId(), op.getOrderProdId(),
					op.getOrderProductDetail().size() });
			for (OrderProductDetail opd : op.getOrderProductDetail()) {
				try {
					String filename = opd.getOrderId() + "_" + opd.getProdId() + "_" + opd.getDetailTp() + ".jpg";
					logger.debug("opDetail:{}, file:{}", opd.getOrderDetailId(), filename);
					if (capFile.contains(filename)) {
						// by pass
					} else {
						objs.put("oProdDetail", opd);
						// 商品類別: 0主商品, 1預購, 2贈品 , 3加購, 4活動, 5满额购, 6N選m
						if ("2".equals(opd.getDetailTp())) {
							// by pass
						} else {
							Element xml = DocumentHelper.createElement("CaptureImage");
							xml.addElement("memberId").setText(memberId);
							xml.addElement("filename").setText(filename);
							if ("3".equals(opd.getDetailTp())) {
								xml.addElement("url").setText(velocityService.formatByStringTemplate(productAddonUrl, objs));
							} else if ("5".equals(opd.getDetailTp())) {
								CampaignProduct cp = campaignProductService.getProduct(opd.getProdId());
								objs.put("promote", cp);
								xml.addElement("url").setText(velocityService.formatByStringTemplate(productPromoteUrl, objs));
							} else if ("6".equals(opd.getDetailTp())) {
								// TODO: 其實應該只抓虛擬主商品
								xml.addElement("url").setText(velocityService.formatByStringTemplate(productNMUrl, objs));
							} else {
								xml.addElement("url").setText(velocityService.formatByStringTemplate(productUrl, objs));
							}
							batchJobService.save("CaptureImage", xml.asXML(), null, order.getOrderId());
							capFile.add(filename);
						}
					}
				} catch (Throwable e) {
					e.printStackTrace();
					logger.error("capture fail. memberId:{}, order:{}, product:{}", new Object[] { memberId, opd.getOrderId(),
							opd.getProdId() });
				}
			}
		}
	}

	private String toXML(Orders order) {
		String xml = null;
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			BeanWriter beanWriter = new BeanWriter(baos);
			beanWriter.enablePrettyPrint();
			beanWriter.write(order);
			xml = baos.toString();
			beanWriter.flush();
			baos.flush();
			beanWriter.close();
			baos.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return xml;

	}

	@Override
	@Transactional(readOnly = false)
	public boolean updateInvoice(String orderId, Date invoiceDt, String invoiceNumber) throws CoreException {
		// TODO logo update invoice
		Orders order = this.get(orderId);
		if (null == order.getInvoiceDt()) {
			order.setInvoiceDt(invoiceDt);
		}
		order.setInvoiceNumber(invoiceNumber);
		this.update(order);
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean updateOrder(Orders order, String logmsg) throws CoreException {
		if (order.isSync()) {
			throw new CoreException("订单已送出无法取消，请改退货处理");
		}
		// TODO 异动通知
		this.update(order);
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean updateOrderSt(String orderId, String orderStCode) throws CoreException {
		String[] finalStatus = { "70", "80", "81", "82" };
		if (null == this.get(orderId)) {
			return false;
		} else {
			Orders order = this.get(orderId);
			try {
				// 檢查訂單狀態是否合理
				checkOrderStatus(order, orderStCode);
			} catch (Exception e) {
				return false;
			}
			if (StringUtils.indexOfAny(order.getOrderSt(), finalStatus) == -1) {// 最終狀態是不可逆的
				order.setOrderSt(orderStCode);
				// 异动为等待配货时要写入同步时间
				if ("20".equals(orderStCode) && order.getSyncDt() == null) {
					order.setSyncDt(new Date());
				}
				if ("10".equals(orderStCode)) {// 等待付款状态则重设payemnt deadline
					// 付款期限：線上支付: 24hr; 匯款/ATM/郵區 : 7x24 hr
					if ("10".equals(order.getPaymentTp()) || "20".equals(order.getPaymentTp())
							|| "30".equals(order.getPaymentTp()) || "60".equals(order.getPaymentTp())) {
						Date dead7 = DateUtil.getTodayAddDays(7).getTime();
						if (DateUtil.checkDateBetween(new Date(), DateUtil.convertStringToDate("yyyyMMddHHmmss", "20110201000000"),
								DateUtil.convertStringToDate("yyyyMMddHHmmss", "20110209235959"), true, true)
								&& ("10".equals(order.getPaymentTp()) || "20".equals(order.getPaymentTp()))) {
							dead7 = DateUtil.getTodayAddDays(14).getTime();
						}
						dead7 = DateUtil.getLastTimestamp(Calendar.HOUR_OF_DAY, dead7);
						order.setDeadline(dead7);
					} else {
						Date dead1 = DateUtil.getTodayAddDays(1).getTime();
						dead1 = DateUtil.getLastTimestamp(Calendar.HOUR_OF_DAY, dead1);
						order.setDeadline(dead1);
					}
				}

				this.update(order);
				return true;
			} else {
				return false;
			}

		}
	}

	@Override
	@Transactional(readOnly = false)
	public String updateOrderStatus(Order o) {
		Orders order = (Orders) baseMgr.get(Orders.class, o.getOrderId());

		String status = "";
		boolean ignoreUpdateOrder = false;
		boolean updateLogisticCompany = false;
		boolean hasExecutedCreateShipException = false;
		boolean hasExecutedSendProductArrive = false;
		SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
		for (OProduct oop : o.getProduct()) {
			OrderProduct op = (OrderProduct) baseMgr.get(OrderProduct.class, oop.getOrderProdId());
			if (op.getLogisticSt().equals("40") || op.getLogisticSt().equals("90")) {
				logger.warn("This Order's logistic status was finished! Can't update again!orderId:" + op.getOrderId()
						+ ";orderProdId:" + op.getOrderProdId());
			}
			if (OProduct.SALES_LOGISTIC_STATUS_CANCEL.equals(oop.getLogisticSt())) {
				/*
				 * 1.如何取消？ 要透過service order？ 一樣用4號單 2.這狀態已經完成退款？還沒退款
				 */

				status = "80";
				String calcelReason = o.getCancelReason();

				// 檢查訂單狀態是否合理
				checkOrderStatus(order, status);
				if (!hasExecutedCreateShipException) {
					// 產生3號取消單
					// TODO
					createCancelServiceOrder(order, calcelReason);
					hasExecutedCreateShipException = true;
				}
			} else if (OProduct.SALES_LOGISTIC_STATUS_ABNORMAL.equals(oop.getLogisticSt())) {
				/*
				 * 此狀態是最後狀態
				 */
				status = "70";
				// 檢查訂單狀態是否合理
				checkOrderStatus(order, status);
				serviceOrderService.sendMail("orderNotSuccess", "订单" + order.getOrderId() + " 交易未成功，系统已自动取消订单", order);

				if (!hasExecutedCreateShipException) {
					createShipExceptionServiceOrder(order, o.getCancelReason());
					hasExecutedCreateShipException = true;
				}
			} else if (OProduct.SALES_LOGISTIC_STATUS_PICK_FAIL.equals(oop.getLogisticSt())) {
				/*
				 * 暫時設定為user手動取消： 因為客服會跟客戶聯絡詢問是否等待或取消 等待的話，不會到前台來
				 */

				status = "81";
				// 檢查訂單狀態是否合理
				checkOrderStatus(order, status);
				if (!hasExecutedCreateShipException) {
					createShipExceptionServiceOrder(order, o.getCancelReason());
					Member member = (Member) baseMgr.get(Member.class, order.getMemberId());
					if (member.getMobile() != null && member.getMobile().length() > 0) {
						String msg = "您好，您在耀点100的订单" + order.getOrderId() + "由于商品缺货，暂时无法为您配货，客服人员将尽快与您联系说明，造成不便，我们深感抱歉！";
						smsService.sendSms(member.getMobile(), msg, order.getOrderId());
					}
					hasExecutedCreateShipException = true;
				}

			} else if (OProduct.SALES_LOGISTIC_STATUS_IN_TRANSIT.equals(oop.getLogisticSt())) {
				// if ("30".equals(order.getOrderSt()) && op.getLogisticRefNum() != null
				// && op.getLogisticRefNum().equals(oop.getLogisticRefNum())) {
				if ("30".equals(order.getOrderSt())) {

					updateLogisticCompany = true;
				}
				if ("30".equals(order.getOrderSt()) && oop.getLogisticRefNum() == null) {
					// 狀態相同
					// IGNORE, 但若logisticRefNum不同，则仍要update
					ignoreUpdateOrder = true;
				} else {
					// if (op.getLogisticSt() == null || op.getLogisticSt().equals("") || op.getLogisticSt().equals(" ")) {
					status = "30";
					// 檢查訂單狀態是否合理
					checkOrderStatus(order, status);
					if (!hasExecutedSendProductArrive && !order.getOrderSt().equals("30")) {
						Member member = (Member) baseMgr.get(Member.class, order.getMemberId());
						op.setLogisticSendDt(oop.getLogisticSendDt());
						op.setLogisticCompany(oop.getLogisticCompany());
						op.setLogisticRefNum(oop.getLogisticRefNum());
						sendMailForProductArrive(order);
						if (member.getMobile() != null && member.getMobile().length() > 0 && !"30".equals(order.getReceiverTp())) {
							String msg = "您在耀点100的订单" + order.getOrderId() + "，商品已发出，将于近日送达！（您可用快递单号：" + oop.getLogisticRefNum()
									+ "至订单页查询发货进度）";
							smsService.sendSms(member.getMobile(), msg, order.getOrderId());
						}
						// 更新VirtualBalance 財會核可日期
						if (order.getMyWallet().compareTo(new BigDecimal(0)) > 0) {
							memberService.updateVirtualBalanceDate(order.getOrderId(), member.getMemberId(), order.getOrderProduct()
									.get(0).getLogisticSendDt());
						}
						hasExecutedSendProductArrive = true;
					}
					// } else {
					// throw new Exception("deliver exception：" + op.getLogisticSt() + "->" + oop.getLogisticSt());
					// }
				}
				// } else if (OProduct.SALES_LOGISTIC_STATUS_NOT_READY.equals(oop.getLogisticSt())) {
				// status = "20";
			} else if (OProduct.SALES_LOGISTIC_STATUS_ARRIVE.equals(oop.getLogisticSt())) {
				// 達芙妮到店取貨
				if ("30".equals(order.getReceiverTp())) {
					if ("32".equals(order.getOrderSt())) {
						// 狀態相同
						// IGNORE
						ignoreUpdateOrder = true;
					} else {

						// 更新訂單狀態到
						status = "32";
						// 檢查訂單狀態是否合理
						checkOrderStatus(order, status);
						if (!"30001231".equals(df.format(oop.getLogisticFinalDt()))) {
							order.setLogisticFinalDt(oop.getLogisticFinalDt());
						}
					}

				} else {
					if ("35".equals(order.getOrderSt())) {
						// 狀態相同
						// IGNORE
						ignoreUpdateOrder = true;
					} else {
						if (op.getLogisticSt().equals(OProduct.SALES_LOGISTIC_STATUS_IN_TRANSIT)) {
							// 過15天後，將狀態改為交易成功
							// 貨已送達
							status = "35";
							// 檢查訂單狀態是否合理
							checkOrderStatus(order, status);
							// 若是貨到付款，將mustPay copy至cash
							if (order.getPaymentTp().equals("30") || order.getPaymentTp().equals("60")) {
								order.setCash(order.getMustPay());
								// 已付款
								order.setPaymentSt("10");
								// 將cash拆分到orderProduct及orderDetail
								order = calcOrderCash(order);
							}
							// 精品tag
							if ("on".equalsIgnoreCase(ServerValue.getUpdateProdStByERP())) {
								op.setProdStatus(oop.getProdStatus());
							}
						} else {
							throw new RuntimeException("deliver exception(order:" + order.getOrderId() + ")：" + op.getLogisticSt()
									+ "->" + oop.getLogisticSt());
						}
					}
				}
			} else if (OProduct.SALES_LOGISTIC_STATUS_SIGNED.equals(oop.getLogisticSt())) {
				if ("30".equals(order.getReceiverTp()) && !"32".equals(order.getOrderSt())) {
					throw new RuntimeException("DAPHNE order(" + order.getOrderId() + ")：" + order.getOrderSt() + " -> 35");
				}
				if ("35".equals(order.getOrderSt())) {
					// 狀態相同
					// IGNORE
					ignoreUpdateOrder = true;
				} else {
					// 更新訂單狀態到
					status = "35";
					// 檢查訂單狀態是否合理
					checkOrderStatus(order, status);
					// 精品tag
					if ("on".equalsIgnoreCase(ServerValue.getUpdateProdStByERP())) {
						op.setProdStatus(oop.getProdStatus());
					}
				}
				if (!"30001231".equals(df.format(oop.getLogisticSignDt()))) {
					order.setLogisticSignDt(oop.getLogisticSignDt());
				}
			} else if (OProduct.SALES_LOGISTIC_STATUS_DPN_RESEND.equals(oop.getLogisticSt())) {
				CommonCriteria cc = new CommonCriteria();
				cc.addEq("orderId", order.getOrderId());
				cc.addEq("srcType", 7);
				boolean isExistResend = serviceOrderService.getList(0, -1, cc, null).size() > 0 ? true : false;
				if (isExistResend) {
					// 狀態相同
					// IGNORE
					ignoreUpdateOrder = true;
				} else {
					// 達芙妮物流重發單
					checkOrderStatus(order, order.getOrderSt());
					if (!hasExecutedCreateShipException) {
						// 產生7號物流
						// TODO
						createResendServiceOrder(order, "重发物流单");
						hasExecutedCreateShipException = true;
					}
				}

			}

			if (!ignoreUpdateOrder) {

				op.setLogisticCompany(oop.getLogisticCompany());
				op.setLogisticNo(oop.getLogisticNo());
				op.setLogisticRefNum(oop.getLogisticRefNum());
				op.setLogisticRemark(oop.getLogisticRemark());
				op.setLogisticSt(oop.getLogisticSt());

				if ("30".equals(order.getReceiverTp())) {// 達芙妮的final是等客人簽收算起
					if (!"30001231".equals(df.format(oop.getLogisticSignDt()))) {
						op.setLogisticFinalDt(oop.getLogisticSignDt());
					}
				} else {
					if (!"30001231".equals(df.format(oop.getLogisticFinalDt()))) {
						op.setLogisticFinalDt(oop.getLogisticFinalDt());
					}
				}

				if (!"30001231".equals(df.format(oop.getLogisticSendDt()))) {
					op.setLogisticSendDt(oop.getLogisticSendDt());
				}

				for (ODetail ood : oop.getDetail()) {
					OrderProductDetail opd = (OrderProductDetail) baseMgr.get(OrderProductDetail.class, ood.getOrderDetailId());
					opd.setErpCost(ood.getErpCost());
					if (ood.getVendId() == null) {
						opd.setVendId(" ");
					} else {
						opd.setVendId(ood.getVendId());
					}
					// 記錄出貨單號
					if (OProduct.SALES_LOGISTIC_STATUS_IN_TRANSIT.equals(oop.getLogisticSt())
							|| OProduct.SALES_LOGISTIC_STATUS_DPN_RESEND.equals(oop.getLogisticSt())) {
						opd.setShippingOid(ood.getShippingOid());
						String shippingLineOidString = ood.getShippingLineOid();
						Long shippingLineOid = null;
						if (StringUtils.isNotBlank(shippingLineOidString)) {
							shippingLineOid = Long.valueOf(shippingLineOidString);
						}
						opd.setShippingLineOid(shippingLineOid);
					}

					baseMgr.update(opd);
				}
				baseMgr.update(op);
			}
			if (updateLogisticCompany) {
				op.setLogisticCompany2(oop.getLogisticCompany2());
				op.setLogisticNo(oop.getLogisticNo());
				baseMgr.update(op);
			}
		}
		if (!ignoreUpdateOrder) {
			// 增加判斷 status 是否為 blank, 目前應該是 20 未多加判斷
			if (StringUtils.isNotBlank(status)) {
				order.setOrderSt(status);
				if ("35".equals(status)) {// 商品已送达, 发送积分
					giveOrderBonus(order);
				}
			}
			baseMgr.update(order);
			if ("30".equals(order.getReceiverTp()) && "32".equals(order.getOrderSt())) {
				dpnService.sendNotice("order.arriveStore", order);
			}
		}
		return "true";

	}

	private void createResendServiceOrder(Orders order, String desc) {
		createServiceOrder(order, desc, ServiceOrders.SERVICE_TYPE.RESEND.getValue(), " ");

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#addPromoteProduct(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Orders addPromoteProductAndResync(String orderId, String productId, String categoryPath) throws CoreException {
		Orders order = get(orderId);
		if (order != null) {
			Product prod = productService.get(productId);
			Specification spec = null;
			SpecificationInventory si = null;
			for (SpecificationInventory siTmp : productService.getSpecificationInventoryMap(productId).values()) {
				if (siTmp.getInventory().intValue() > 0) {
					spec = siTmp.getSpecification();
					si = siTmp;
					break;
				}
			}
			if (si == null || si.getInventory() <= 0) {
				throw new CoreException("errors.specInventory.product.zero", productId);
			}

			if (prod != null && spec != null) {
				if (verifyShippingDelayOrder(orderId)) {
					Shelf shelf = new Shelf();
					shelf.setShelfPrice(BigDecimal.ZERO);
					OrderProduct op = new OrderProduct(prod, spec, categoryPath, shelf);
					OrderProductDetail opd = new OrderProductDetail(prod, spec, shelf);
					order.addProduct(op);
					op.addDetail(opd);

					if ("25".equals(order.getOrderSt())) {
						order.setSync(false);
						order.setOrderSt("20");
					} else {
						throw new CoreException("errors.order.status", orderId, order.getOrderSt());
					}
					si.setSoldInventory(si.getSoldInventory() + 1);
					productService.saveSpecificationInventory(si);
					save(order);
					// 寄信

					try {
						Member member = (Member) baseMgr.get(Member.class, order.getMemberId());
						Map objs = new HashMap();
						objs.put("order", order);
						objs.put("member", member);
						objs.put("basehref", "http://" + member.getDomainSrc());
						objs.put("contextpath", ServerValue.getFrontContextPath());
						Mail mail = velocityService.formatToMail("order.apologyForDelay", objs);
						if (member != null && StringUtils.isNotBlank(member.getEmail())) {
							mail.setTo(member.getSendEmail());
							mail.setFrom(envParameters.getEmailFromSystem());
							mailService.save(mail);
						}
					} catch (Exception e) {
						throw new CoreException(orderId + "延迟发货寄信异常");
					}
				} else {
					throw new CoreException("errors.order.verify", orderId);
				}
			} else {
				throw new CoreException(prod + ":" + spec + ":" + si + ":異常！！");
			}
		} else {
			throw new CoreException(orderId + ": 訂單異常");
		}
		return order;
	}

	@Override
	@Transactional(readOnly = false)
	public Orders addBonusForDelayOrder(String orderId) throws CoreException {
		Orders order = get(orderId);
		if (order != null) {
			if (verifyShippingDelayOrder(orderId)) {
				// if ("25".equals(order.getOrderSt())) {
				// order.setSync(false);
				// order.setOrderSt("20");
				// } else {
				// throw new CoreException("errors.order.status", orderId, order.getOrderSt());
				// }
				Member member = (Member) baseMgr.get(Member.class, order.getMemberId());
				// 发送会员积分10*100=1000点
				Bonus bonus = new Bonus();
				bonus.setMemberId(member.getMemberId());
				bonus.setTrxAmount(new BigDecimal(1000));
				bonus.setTrxType("ORDER_FEEDBACK");
				bonus.setTrxDate(new Date());
				bonus.setStartDate(DateUtils.addDays(new Date(), 1));
				bonus.setOrderId(orderId);
				bonus.setDescription("延迟出货补偿");
				bonus.setExpireDate(DateUtils.addDays(new Date(), 31));
				bonus = memberService.saveOrUpdateBonusNotRecalculate(bonus);
				// 寄信
				try {
					Map<String, Object> objs = new HashMap<String, Object>();
					objs.put("order", order);
					objs.put("member", member);
					objs.put("basehref", "http://" + member.getDomainSrc());
					objs.put("contextpath", ServerValue.getFrontContextPath());
					Mail mail = velocityService.formatToMail("order.apologyForDelayBonus", objs);
					if (member != null && StringUtils.isNotBlank(order.getReceiverEmail())) {
						mail.setTo(order.getReceiverEmail());
						mail.setFrom(envParameters.getEmailFromSystem());
						mailService.save(mail);
					}
				} catch (Exception e) {
					throw new CoreException(orderId + "延迟发货寄信异常");
				}

				try {
					if (member.getMobile() != null && member.getMobile().length() != 0) {
						StringBuffer smsMsg = new StringBuffer();
						smsMsg.append("亲爱的耀点100用户，感谢您的支持。因近日订单量激增, 您编号为").append(order.getOrderId()).append(
								"的订单将会延迟配送。我们对此十分抱歉。等侯期间，网站将及时更新订单状态以便查询。若您对订单有其他疑问，请致电客服热线4001-168-100。我们愿竭诚为您服务！【耀点100】");
						this.smsService.sendSms(member.getMobile(), smsMsg.toString(), order.getOrderId());
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

			} else {
				throw new CoreException("errors.order.verify", orderId);
			}
		} else {
			throw new CoreException(orderId + ": 訂單異常");
		}
		return order;
	}

	@Transactional(readOnly = false)
	private boolean verifyShippingDelayOrder(String orderId) {
		try {
			StringBuffer sql = new StringBuffer("insert into EC_SPEC_INVENTORY_VALID (VALID_ID) values (?) ");
			jdbcTemplate.update(sql.toString(), new Object[] { orderId });
		} catch (Exception e) {
			// e.printStackTrace();
			return false;
		}
		return true;
	}

	/*
	 * COD訂單審核 首购的订义: 1.365天内, 2.该会员 3.交易完成的订单 ==0 表示为首购
	 */
	@Override
	@Transactional(readOnly = false)
	public boolean verifyOrder(String days, String memberId, String orderSt) {
		String hql = "from Orders where createDate between sysdate-? and sysdate and memberId = ? and orderSt in(?)";
		Object[] verifyOrderAy = baseMgr.queryByHql(hql, new Object[] { days, memberId, orderSt });
		if (verifyOrderAy.length == 0) {
			return true;
		} else {
			return false;
		}
	}

	@Transactional(readOnly = false)
	public boolean validAddressDataNew(Orders order) {

		// 如果找不到版本編號,表示省市區不在deliveryRule中
		String verifyOrder = deliveryRuleService.findAddressVersion(order);
		if (StringUtils.isBlank(verifyOrder)) {
			return false;
		} else {
			ViewDeliveryRule viewDeliveryRule = deliveryRuleService.canUseCodByOrderId(order.getOrderId());
			if ("30".equals(order.getPaymentTp()) && "N".equals(viewDeliveryRule.getIsCod())) {
				return false;
			}
			if ("60".equals(order.getPaymentTp()) && "N".equals(viewDeliveryRule.getIsPos())) {
				return false;
			}
			return true;
		}
	}

	/**
	 * 恶意订单：订单处理审核 -达芙妮到店不检查地址
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	@Transactional(readOnly = false)
	public String validBadManOrder(Orders order) throws Exception {
		if ("on".equals(ServerValue.getBlockOrder())) {
			if (!"true".equals(memberService.badMemberCheck(order.getMemberId()))) {
				// 帐号黑名单
				// throw new Exception("您的帐号异常, 请洽客服人员");
				throw new Exception("errors.order.badman");
			}
			// 达芙妮不检查地址
			if ("30".equals(order.getReceiverTp()) || StringUtils.isNotBlank(order.getStoreId())) {
				return "true";
			} else {
				String result = memberService.badOrderCheck(order.getMemberId(), order.getReceiverAddr(), order
						.getReceiverMobile(), order.getReceiverPhone());
				if (!"true".equals(result)) {
					return result;
				} else {
					return "true";
				}
			}
		} else {
			return "true";
		}
	}

	public ObjectDao<OrderUserData> getOrdersUserDataDao() {
		return ordersUserDataDao;
	}

	public void setOrdersUserDataDao(ObjectDao<OrderUserData> ordersUserDataDao) {
		this.ordersUserDataDao = ordersUserDataDao;
	}

	/**
	 * 客服修改订单 1。取消原订单（已付款将款项退回账户余额／未付款直接取消） 2。成立新订单（由我的账户余额：原订单扣除，若不需再付款则付款完成并待同步至后台／仍有金额需付则待使用者付款：再选择付款方式）
	 */
	@Override
	@Transactional(readOnly = false)
	public void csrUpdateOrderAndShipfare(Orders origin, Orders newOrder, String userId, String clientIp, String b2eId,
			List<OrderProduct> cancelProducts) {
		CsrUpdateOrderLog orderLog = (CsrUpdateOrderLog) baseMgr.get(CsrUpdateOrderLog.class, origin.getOrderId());
		if (orderLog != null && orderLog.isEnable()) {
			orderLog.setEnable(false);
			baseMgr.update(orderLog);

		} else {
			throw new RuntimeException("本订单已不允许更改！");
		}

		// 取消原订单并成立8号服务单！？
		String description = "客服修改订单";
		String reason = "客服修改订单";
		serviceOrderService.cancelOrderByCsrUpdateOrder(origin, description, reason, origin.getMemberId(), clientIp, b2eId,
				userId, cancelProducts);
		try {
			// 付款并成立新订单
			this.save(newOrder);
			// 重新计算要发送的会员积分&新增一笔订单的积分发送、折抵规则资料
			if (newOrder.getBonus().compareTo(BigDecimal.ZERO) == 1) {
				OrderBonusCampaign obcSrc = origin.getOrderBonusCampaign();
				OrderBonusCampaign obcNew = new OrderBonusCampaign();
				BeanUtils.copyProperties(obcSrc, obcNew, new String[] { "orderId", "giveBonus" });
				obcNew.setGiveBonus(calcGiveBonus(newOrder));
				obcNew.setOrderId(newOrder.getOrderId());
				orderBonusCampaignDao.save(obcNew);
				newOrder.setOrderBonusCampaign(obcNew);
			}
			// 物流商代碼
			String logisticProviderTp = deliveryRuleService.logisticProviderTpByOrderId(newOrder.getOrderId());
			newOrder.setLogisticProviderTp(logisticProviderTp);
			// 拆单更新资料
			newOrder.setJoinMustPay(newOrder.getMustPay());
			newOrder.setJoinOrders(newOrder.getOrderId());
			// 计算商品的礼品卡、账户余额、积分、运费、cod手续费、分期手续费、mustpay摊提费用比例
			newOrder = calcOrderProduct(newOrder);
			update(newOrder);
			this.afterOrders(newOrder, newOrder.getMyWallet(), null, newOrder.getBonus(), newOrder.getGiftcardBalance());
		} catch (Exception e) {
			e.printStackTrace();
			// logger.info("execption:{}", e.getMessage());
			throw new RuntimeException(e.getLocalizedMessage() + ",Csr update order failed! Pay by myWallet failed.");

		}

		int stockNum = jdbcTemplate.queryForInt("select count(*) from EC_SPEC_INVENTORY_VALID where VALID_ID = '"
				+ origin.getOrderId() + "outStock" + "'");
		if (stockNum == 0) {
			StringBuffer sql = new StringBuffer("insert into EC_SPEC_INVENTORY_VALID (VALID_ID) values (?) ");
			jdbcTemplate.update(sql.toString(), new Object[] { origin.getOrderId() + "outStock" });

			// 发送会员积分10*100=1000点
			Bonus bonus = new Bonus();
			bonus.setMemberId(newOrder.getMemberId());
			bonus.setOrderId(newOrder.getOrderId());
			bonus.setStartDate(DateUtils.addDays(new Date(), 1));
			bonus.setTrxDate(new Date());
			bonus.setExpireDate(DateUtils.addDays(bonus.getStartDate(), 30));
			bonus.setTrxAmount(new BigDecimal(1000));
			bonus.setDescription("断货补偿");
			bonus.setTrxType("ORDER_FEEDBACK");
			try {
				memberService.saveOrUpdateBonus(bonus);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		renewOrderMail(origin, newOrder, cancelProducts);

		try {
			Member member = (Member) baseMgr.get(Member.class, newOrder.getMemberId());
			if (member.getMobile() != null && member.getMobile().length() != 0) {
				StringBuffer smsMsg = new StringBuffer();
				smsMsg.append("亲爱的耀点100用户，很抱歉通知您，您的订单").append(origin.getOrderId()).append("部分商品目前无货，为了让您早日收到其余有货商品，我们将转由新订单")
						.append(newOrder.getOrderId()).append("为您配送。原订单取消后，所有无货商品已支付的金额将会退回到您的耀点100帐户。【耀点100】");
				this.smsService.sendSms(member.getMobile(), smsMsg.toString(), origin.getOrderId());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		int totalCancelProduct = 0;
		for (OrderProduct op : cancelProducts) {
			for (OrderProductDetail opd : op.getOrderProductDetail()) {
				if (!opd.getDetailTp().equals("2")) {
					totalCancelProduct++;
				}
			}

		}
		// String msg = "耀点100会员您好，我们已取消您订单" + origin.getOrderId() + "中的" + totalCancelProduct
		// + "笔商品，您可进入订单明细查询更新后之内容，造成您的困扰，我们深感抱歉。";
		// Member member = (Member) baseMgr.get(Member.class, origin.getMemberId());
		// if (member.getMobile() != null && member.getMobile().length() > 0 && !"30".equals(origin.getReceiverTp())) {
		// smsService.sendSms(member.getMobile(), msg, origin.getOrderId());
		// }
		// 转移coupon
		for (OrderProduct op : newOrder.getOrderProduct()) {
			if (op.getCouponId() != null) {
				couponService.transferCoupon(origin, newOrder, op.getCouponId());
			}
		}
	}

	private void renewOrderMail(Orders origin, Orders newOrder, List<OrderProduct> cancelProducts) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("origin", origin);
		map.put("order", newOrder);
		map.put("domainSrc", newOrder.getDomainSrc());
		map.put("baseHref", "http://" + newOrder.getDomainSrc());
		map.put("cancelProducts", cancelProducts);
		map.put("orderDt", df.format(newOrder.getOrderDt()));
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("orderId", newOrder.getOrderId());
		List<OrderProductDetail> getOrderProdDetailList = getOrderProdDetailList(0, -1, crit,
				new String[] { "prodSeq asc" });
		map.put("orderDetails", getOrderProdDetailList);
		map.put("paymentTpMenu", paymentTpMenu);
		map.put("deadline", FastDateFormat.getInstance(EcConstant.PATTERN_TIMESTAMP).format(newOrder.getDeadline()));
		Mail mail = velocityService.formatToMail("renewOrder", map);
		mail.setFrom(envParameters.getEmailFromSystem());
		mail.setTo(newOrder.getReceiverEmail());

		mailService.save(mail);
	}

	@Override
	@Transactional(readOnly = false)
	public void lockOrderForUpdate(String orderId, String result) {
		if (!"true".equals(result)) {
			throw new RuntimeException("订单不允许更改！");
		} else {
			try {
				CsrUpdateOrderLog orderLog = (CsrUpdateOrderLog) baseMgr.get(CsrUpdateOrderLog.class, orderId);
				if (orderLog != null) {
					if (!orderLog.isEnable()) {
						throw new RuntimeException();
					}
				} else {
					orderLog = new CsrUpdateOrderLog();
					orderLog.setOrderId(orderId);
					orderLog.setLockDate(new Date());
					orderLog.setEnable(true);
					baseMgr.save(orderLog);
				}
			} catch (Exception e) {
				throw new RuntimeException("订单不允许重覆修改！");
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public void unlockOrder(CsrUpdateOrderLog orderLog) {
		orderLog.setEnable(false);
		baseMgr.update(orderLog);
	}

	@Override
	@Transactional(readOnly = false)
	public void remindPayment(Orders order) {
		sendMail("order.remindPayment", "订单" + order.getOrderId() + " 未支付提醒", order);
	}

	@Override
	@Transactional(readOnly = false)
	public void remindPaymentSMS(Orders order) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		String deadlineT = df.format(order.getDeadline());
		String msg = "您好，为避免您在耀点100的订单" + order.getOrderId() + "因付款逾期而被取消，请在" + deadlineT + "前完成付款。若您已支付，请忽略此提醒。";
		if (StringUtils.isNotBlank(order.getReceiverMobile())) {
			smsService.sendSms(order.getReceiverMobile(), msg, order.getOrderId());
		}
	}

	private void sendMail(String velocityTemplate, String mailSubject, Orders order) {
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("order", order);
		List<OrderProductDetail> getOrderProdDetailList = new ArrayList();
		for (OrderProduct op : order.getOrderProduct()) {
			getOrderProdDetailList.addAll(op.getOrderProductDetail());
		}
		contentMap.put("orderdetails", getOrderProdDetailList);
		// contentMap.put("customerFax", ServerValue.getCustomerFax());
		// contentMap.put("customerTel", ServerValue.getCustomerTel());
		contentMap.put("paymentTpMenu", menuService.get("Order.PaymentTp"));
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("basehref", "http://" + order.getDomainSrc());
		Mail mail = velocityService.formatToMail(velocityTemplate, contentMap);
		mail.setFrom(envParameters.getEmailFromSystem());
		if ("order.badMan".equals(velocityTemplate)) {// 黑名單
			mail.setTo("blockorder@yaodian100.com");// 名單的部份暫時使用：greylist@yaodian100.com
		} else {
			mail.setTo(order.getReceiverEmail());
		}
		mail.setSubject(mailSubject);
		mailService.save(mail);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#revertOrder(java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Orders revertOrder(String orderId) throws CoreException {
		Orders order = get(orderId);
		// 被取消, 未付款
		if (("80".equals(order.getOrderSt()) || "81".equals(order.getOrderSt()) || "82".equals(order.getOrderSt()))
				&& "00".equals(order.getPaymentSt()) && order.getMyWallet().floatValue() == 0
				&& order.getBonus().floatValue() == 0) {
			// 還原庫存(cancelInventory)
			for (OrderProduct op : order.getOrderProduct()) {
				for (OrderProductDetail opd : op.getOrderProductDetail()) {
					try {
						Integer update = (Integer) baseMgr.executeHql(
								"update SpecificationInventory a set a.modifyDate=sysdate, a.cancelInventory = a.cancelInventory - ? "
										+ " where (availableInventory + cancelInventory - soldInventory) >= ?"
										+ " and a.productId = ? and specId = ? ", new Object[] { opd.getQty(), opd.getQty(),
										opd.getProdId(), Long.parseLong(opd.getProdSpecId()) });
						if (update == 0) {
							throw new CoreException("数量不足！！", opd.getProdId(), opd.getProdSpecId());
						}
					} catch (Exception ee) {
						throw new CoreException("数量不足！！", opd.getProdId(), opd.getProdSpecId());
					}
				}

				// // 若 OrderProduct 中 coupon 栏位有值, 因为取消还原, 尝试再次使用
				if (StringUtils.isNotBlank(op.getCouponId())) {
					String couponItemId = null;
					List<CouponItem> couponItems = couponService.getItems(order.getMemberId(), Arrays.asList(op));
					for (CouponItem ci : couponItems) {
						if (ci.getCoupon().getUuid().equals(op.getCouponId())) {
							couponItemId = ci.getUuid();
							break;
						}
					}
					if (StringUtils.isBlank(couponItemId)) {
						throw new CoreException("已无 coupon 可供还原");
					}
					couponService.useCoupon(couponItemId, order.getMemberId(), orderId);
				}
			}
			order.setOrderSt("10");
			order.setSync(false);
			if (StringUtils.isBlank(order.getMemo())) {
				order.setMemo("");
			}
			if (AdminHelper.getUser() != null) {
				String now = DateUtil.convertDateToString(DateUtil.PATTERN_DATE_TIME, new Date());
				order.setMemo(order.getMemo() + " " + AdminHelper.getUser().getUsername() + " " + DateUtil.getCurrentTime()
						+ "还原");
			}

			Calendar deadline = Calendar.getInstance();
			deadline.setTimeInMillis(System.currentTimeMillis());
			deadline.add(Calendar.DATE, 1);
			order.setDeadline(deadline.getTime());
		} else {
			throw new CoreException("状态错误！！", order.getOrderSt(), order.getPaymentSt());
		}
		return order;
	}

	public MailBannerService getMailBannerService() {
		return mailBannerService;
	}

	public void setMailBannerService(MailBannerService mailBannerService) {
		this.mailBannerService = mailBannerService;
	}

	public ObjectDao<OrderCreditCardCampaign> getOrderCreditCardCampaignDao() {
		return orderCreditCardCampaignDao;
	}

	public void setOrderCreditCardCampaignDao(ObjectDao<OrderCreditCardCampaign> orderCreditCardCampaignDao) {
		this.orderCreditCardCampaignDao = orderCreditCardCampaignDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#chkVolumeOfOrderDetail(java.lang.String)
	 */
	@Override
	public Map<String, String> chkVolumeOfOrderDetail(String orderId) throws CoreException {
		StringBuffer sb = new StringBuffer();
		List<String> attrs = new ArrayList<String>();
		sb.append("select p.product_id,p.product_name,p.product_weight,p.product_volume ");
		sb.append("from ec_product_main p,ec_order_detail d ");
		sb.append("where ");
		sb.append("((p.product_weight / 1000 ) > ? or (p.product_volume / ? ) > ? ) and ");
		// sb.append("(p.product_weight / 1000 ) > ? and ");
		sb.append("p.is_scm <> 'Y' and p.product_id = d.prod_id and d.order_id= ? ");
		attrs.add(ServerValue.getProdWeight());
		attrs.add(ServerValue.getProdVolumeWeight());
		attrs.add(ServerValue.getProdWeight());
		attrs.add(orderId);
		List list = getDao().getSQLQueryByList(sb.toString(), attrs, 0, -1);
		Map<String, String> prodVolumeMap = new HashMap<String, String>();
		if (null != list && list.size() > 0) {
			Object[] obj = null;
			for (int i = 0; i < list.size(); i++) {
				obj = (Object[]) list.get(i);
				prodVolumeMap.put(obj[0].toString(), obj[1].toString());
			}
		}
		return prodVolumeMap;
	}

	@Override
	@Transactional(readOnly = false)
	public void cancelOrderBySystemUser(Orders order, String reason, String memo) throws CoreException {
		order.setOrderSt("80");// cancel order
		if (memo != null) {
			StringBuffer sbMemo = new StringBuffer();
			if (order.getMemo() != null) {
				sbMemo.append(order.getMemo());
			}
			sbMemo.append(" ").append(memo);
			int max = 300; // 欄位最大長度
			if (sbMemo.length() > max) {
				sbMemo.delete(0, sbMemo.length() - max);
				if (sbMemo.length() > 3) {
					sbMemo.delete(0, 3);
					sbMemo.insert(0, "...");
				}
			}
			order.setMemo(sbMemo.toString());
		}
		this.update(order);
		serviceOrderService.returnInventory(order);
		serviceOrderService.cancelOrderBySystem(order.getOrderId(), "订单" + order.getOrderId() + " 已由客服人员取消", reason, order
				.getMemberId(), "SYSTEM", order.getB2eId());// 處理禮券，积分，帳戶餘額
		memberService.updateOrder2PayBalance(order.getMemberId());
		// sendMail("order.cancelOrder", "订单" + order.getOrderId() + " 已由客服人员取消", order);

		// cobranding-onlylady

		String domainSrc = order.getDomainSrc();
		if (!domainSrc.endsWith("yaodian100.com")) {
			if (domainSrc.endsWith("onlylady.com")) {
				Onlylady ol = new Onlylady();
				ol.olCancelOrder(order);
			}
		}
	}

	public Number getOrderMemoSize(CommonCriteria criteria) throws CoreException {
		return orderMemoDao.getListSize(criteria);
	}

	public List<OrderMemo> getOrderMemo(int firstResult, int maxResults, CommonCriteria criteria, String[] sortOrder)
			throws CoreException {
		String[] defaultSort = new String[] { "createDate desc", "memoId desc" };
		if (sortOrder == null) {
			return orderMemoDao.getListPageable(criteria, defaultSort, firstResult, maxResults);
		}
		return orderMemoDao.getListPageable(criteria, sortOrder, firstResult, maxResults);
	}

	@Transactional(readOnly = false)
	public OrderMemo saveOrderMemo(OrderMemo orderMemo) throws CoreException {
		OrderMemo om = null;
		try {
			om = orderMemoDao.save(orderMemo);
		} catch (Exception e) {
			throw new CoreException(orderMemo.getOrderId() + "无法新增讯息");
		}
		return om;
	}

	public ObjectDao<OrderMemo> getOrderMemoDao() {
		return orderMemoDao;
	}

	public void setOrderMemoDao(ObjectDao<OrderMemo> orderMemoDao) {
		this.orderMemoDao = orderMemoDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#chkOrderGrossProfitRate(com.yaodian100.ec.order.entity.Orders)
	 */
	@Transactional(readOnly = false)
	boolean validateOrderGrossProfitRate(Menu systemValueMenu, CartOrders cart, Orders order) throws CoreException {
		if (null != systemValueMenu) {
			Float grossProfitRate = Float.valueOf(systemValueMenu.getOptions().get("fw_lowest_gpm").getMemo1());
			Float totalCost = getOrderTotalCost(order);
			Float totalPay = order.getCash().floatValue() + order.getMyWallet().floatValue()
					+ order.getGiftcardBalance().floatValue() + order.getMustPay().floatValue()
					- order.getShipfare().floatValue();
			// 计算毛利率
			if (totalPay == 0) {// 應付金額=0
				return true;
			}
			if ((((totalPay - totalCost) / totalPay) * 100) < grossProfitRate.floatValue()) {// 小於毛利率
				return true;
			} else {
				return false;
			}
		}
		return false;
	}

	/**
	 * 商品总成本
	 * 
	 * @param orders
	 * @return
	 * @throws CoreException
	 */
	Float getOrderTotalCost(Orders orders) throws CoreException {
		Float totalCost = 0f;
		for (OrderProduct op : orders.getOrderProduct()) {
			for (OrderProductDetail opd : op.getOrderProductDetail()) {
				totalCost = totalCost + (opd.getEcCost().floatValue() * opd.getQty());
			}
		}
		return totalCost;
	}

	@Transactional(readOnly = false)
	public List<Orders> processSuccessTuangouOrder(String tuangouId) throws CoreException {
		List<Orders> orders = new ArrayList<Orders>();
		if (StringUtils.isNotBlank(tuangouId)) {
			CommonCriteria cc = new CommonCriteria();
			cc.addEq("tuangouId", new Long(tuangouId));
			cc.addIn("orderSt", Arrays.asList(new String[] { "00", "10", "20" }));
			cc.addEq("isTuangouSync", false);
			orders = getList(0, -1, cc, new String[] { "orderId" });
			for (Orders order : orders) {
				order.setTuangouSync(true);
				save(order);
				sendTunagouMailAndSms("order.tuangouSuccess", order);
			}
			saveTuangouOpLog(tuangouId, "1");
		}
		return orders;

	}

	@Transactional(readOnly = false)
	public List<Orders> processFailTuangouOrder(String tuangouId) throws CoreException {
		List<Orders> orders = new ArrayList<Orders>();
		if (StringUtils.isNotBlank(tuangouId)) {
			CommonCriteria cc = new CommonCriteria();
			cc.addEq("tuangouId", new Long(tuangouId));
			// cc.addIn("orderSt", Arrays.asList(new String[]{"00","10","20"}));
			cc.addEq("isTuangouSync", false);
			orders = getList(0, -1, cc, new String[] { "orderId" });
			for (Orders order : orders) {
				order.setTuangouSync(true);
				save(order);
				cancelOrderByTuangouFail(order);
				sendTunagouMailAndSms("order.tuangouFail", order);
			}
			saveTuangouOpLog(tuangouId, "2");
		}
		return orders;
	}

	@Transactional(readOnly = false)
	public void cancelOrderByTuangouFail(Orders order) throws CoreException {
		String reason = "团购未成团取消";
		String desc = "团购未成团取消";
		order.setOrderSt("80");// cancel order
		this.update(order);
		serviceOrderService.returnInventory(order);
		serviceOrderService.cancelOrderBySystem(order.getOrderId(), desc, reason, order.getMemberId(), "SYSTEM", order
				.getB2eId());// 處理禮券，积分，帳戶餘額
		memberService.updateOrder2PayBalance(order.getMemberId());
		// sendMail("order.cancelOrder", "订单" + order.getOrderId() + " 已过期取消", order);

		// cobranding-onlylady

		String domainSrc = order.getDomainSrc();
		if (!domainSrc.endsWith("yaodian100.com")) {
			if (domainSrc.endsWith("onlylady.com")) {
				Onlylady ol = new Onlylady();
				ol.olCancelOrder(order);
			}
		}

	}

	/**
	 * 1：成團，2：不成團
	 * 
	 * @param tuangouId
	 * @param opType
	 */
	private void saveTuangouOpLog(String tuangouId, String opType) throws CoreException {

		ShelfTuangou tuangou = tuangouService.get(new Long(tuangouId));
		if (null != tuangou) {
			// 團購上架檔更新結團狀態
			tuangou.setTuangouStatus(opType);
			tuangouService.save(tuangou);
			// 團購操作紀錄新增一筆
			ProductTuangouOP op = new ProductTuangouOP();
			op.setTuangouId(tuangouId);
			op.setProductId(tuangou.getProductId());
			op.setOperatorDesc(opType);
			tuangouService.saveTuangouOPLog(op);

		}

	}

	@Transactional(readOnly = false)
	public void sendTunagouMailAndSms(String template, Orders order) throws CoreException {
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("order", order);
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("basehref", "http://" + order.getDomainSrc());

		Mail mail = velocityService.formatToMail(template, contentMap);
		mail.setFrom(envParameters.getEmailFromSystem());
		mail.setTo(order.getReceiverEmail());
		mailService.save(mail);

		// SMS
		Member member = memberService.get(order.getMemberId());
		if (null != member) {
			if (StringUtils.isNotBlank(member.getMobile())) {
				String msg = "";
				if ("order.tuangouSuccess".equals(template)) {
					msg = "您的团购活动已成立，订单：" + order.getOrderId() + " 将于近日开始出货，感谢您的订购，谢谢!";
				} else if ("order.tuangouFail".equals(template)) {
					msg = "您的团购活动因人数不足无法成团，订单编号" + order.getOrderId() + "，将于三日内退款至厡支付方式，感谢您的订购，谢谢!";
				}
				if (StringUtils.isNotBlank(msg)) {

					smsService.sendSms(member.getMobile(), msg, order.getOrderId());
				}
			}
		}
	}

	@Transactional(readOnly = false)
	public String remindTuangouClose(Orders order) {
		ShelfTuangou tuangou = tuangouService.get(order.getTuangouId());
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		String pmMail = "yaotuangou@yaodian100.com";
		String ccMail = "yaotuangou@yaodian100.com";
		String result = "";
		if (null != tuangou) {
			Product p = productService.get(tuangou.getProductId());
			if (null != p) {
				User u = userService.get(p.getPmID());
				if (null != u) {
					pmMail = u.getEmail();
				} else {
					ccMail = null;
				}
				String body = "已结束团购编号：" + order.getTuangouId() + "尚未处理，请尽速前往核单。团购结束时间：" + df.format(tuangou.getEndDate());
				Mail m = new Mail("活动结束订单尚未同步通知", body, pmMail, ccMail);
				m.setFrom(envParameters.getEmailFromSystem());
				mailService.save(m);

			} else {
				result = "团购所属商品编号不存在，团购编号：" + order.getTuangouId() + ",商编:" + tuangou.getProductId() + "。";
			}
		} else {
			result = "团购编号不存在，团购编号：" + order.getTuangouId() + "。";
		}
		return result;
	}

	@Override
	@Transactional(readOnly = false)
	public String splitOrder(String orderId, String orderProdIds) {
		// 取得旧订单
		Orders orderSrc = get(orderId);
		OrderBonusCampaign obcSrc = null;
		// 取得旧订单积分资料
		obcSrc = orderSrc.getOrderBonusCampaign();
		// 视为成功
		if (orderSrc.getOrderSt().equals("70") || orderSrc.getOrderSt().equals("80") || orderSrc.getOrderSt().equals("81")
				|| orderSrc.getOrderSt().equals("82") || orderSrc.getOrderSt().equals("83")
				|| orderSrc.getOrderSt().equals("90") || orderSrc.getOrderSt().equals("32")) {
			return "true";
		}

		if (StringUtils.equals(orderSrc.getAllowSplit(), "N")) {
			throw new RuntimeException("订单" + orderSrc.getOrderId() + "不允许拆单！");
		}

		// 必须是完成付款
		if (!StringUtils.equals(orderSrc.getPaymentSt(), "10")) {
			throw new RuntimeException("订单必须是完成付款！");
		}

		// 不能是COD
		if (StringUtils.equals(orderSrc.getPaymentTp(), "30") || StringUtils.equals(orderSrc.getPaymentTp(), "60")) {
			throw new RuntimeException("订单不能属于COD！");
		}

		// 補跑訂單金額分配資料
		if (StringUtils.isBlank(orderSrc.getTranslateFlag())) {
			orderSrc.setTranslateFlag("Y");
			orderSrc = calcOrderProduct(orderSrc);
			orderSrc = calcOrderCash(orderSrc);
			update(orderSrc);
		}

		// 拆單
		int orderProdCnt = 0;

		List<Orders> ordersNew = new ArrayList<Orders>();
		String[] newOrders = orderProdIds.split(";");
		for (int i = 0; i < newOrders.length; i++) {
			String _order = newOrders[i];
			// Copy order
			Orders orderNew = new Orders();
			BeanUtils.copyProperties(orderSrc, orderNew, new String[] { "orderId", "orgOrderId", "orderProduct",
					"applyCampaigns", "createDate", "paymentTp" });

			BigDecimal __totalPrice = BigDecimal.ZERO;
			BigDecimal __amount = BigDecimal.ZERO;
			BigDecimal __coupon = BigDecimal.ZERO;
			BigDecimal __discount = BigDecimal.ZERO;

			BigDecimal __weight = BigDecimal.ZERO;
			BigDecimal __bonus = BigDecimal.ZERO;
			BigDecimal __shipfare = BigDecimal.ZERO;
			BigDecimal __myWallet = BigDecimal.ZERO;
			BigDecimal __giftcardBalance = BigDecimal.ZERO;

			List<OrderProduct> orderProdsNew = new ArrayList<OrderProduct>();
			List<OrderProduct> orderProdsOld = orderSrc.getOrderProduct();

			List<com.yaodian100.ec.order.entity.ApplyCampaign> applyCampaignsNew = new ArrayList<com.yaodian100.ec.order.entity.ApplyCampaign>();
			// List<ApplyCampaign> applyCampaignsOld =
			List<com.yaodian100.ec.order.entity.ApplyCampaign> applyCampaignsOld = orderSrc.getApplyCampaigns();

			String[] newOrderProds = _order.split(",");
			for (String _orderProd : newOrderProds) {
				orderProdCnt++;
				// Copy order_product
				for (OrderProduct orderProdSrc : orderProdsOld) {
					if (orderProdSrc.getOrderProdId().longValue() == NumberUtils.toLong(_orderProd)) {
						OrderProduct orderProdNew = new OrderProduct();
						BeanUtils.copyProperties(orderProdSrc, orderProdNew, new String[] { "orderProdId", "orderId", "order",
								"orderProductDetail" });

						__totalPrice = __totalPrice.add(orderProdNew.getTotalPrice());
						__amount = __amount.add(orderProdNew.getAmount());
						__coupon = __coupon.add(orderProdNew.getCoupon());
						__discount = __discount.add(orderProdNew.getDiscount());
						__shipfare = __shipfare.add(orderProdNew.getShipfare());
						__bonus = __bonus.add(orderProdNew.getBonus());
						__myWallet = __myWallet.add(orderProdNew.getMyWallet()).add(orderProdNew.getCash());
						__giftcardBalance = __giftcardBalance.add(orderProdNew.getGiftcardBalance());

						List<OrderProductDetail> orderProdDtlsNew = new ArrayList<OrderProductDetail>();
						List<OrderProductDetail> orderProdDtlsOld = orderProdSrc.getOrderProductDetail();
						// Copy order_product_detail
						for (OrderProductDetail orderProdDtlSrc : orderProdDtlsOld) {
							OrderProductDetail orderProdDtlNew = new OrderProductDetail();
							BeanUtils.copyProperties(orderProdDtlSrc, orderProdDtlNew, new String[] { "orderDetailId", "orderProd",
									"order" });

							orderProdDtlNew.setOrder(orderNew);
							orderProdDtlNew.setOrderProd(orderProdNew);
							orderProdDtlsNew.add(orderProdDtlNew);
							__weight = __weight.add(orderProdDtlNew.getUnitWeight()
									.multiply(new BigDecimal(orderProdDtlNew.getQty())));
						}

						orderProdNew.setOrderProductDetail(orderProdDtlsNew);
						orderProdNew.setOrder(orderNew);
						orderProdsNew.add(orderProdNew);
					}
				}

				// Copy order_campaign
				for (com.yaodian100.ec.order.entity.ApplyCampaign applyCampSrc : applyCampaignsOld) {
					if (validateDataInList(_orderProd, applyCampSrc.getApplyProductIds())) {
						com.yaodian100.ec.order.entity.ApplyCampaign applyCampNew = new com.yaodian100.ec.order.entity.ApplyCampaign();
						// 数量/金额可以不用重新算
						BeanUtils.copyProperties(applyCampSrc, applyCampNew, new String[] { "orderProdId", "orderId", "order" });
						applyCampaignsNew.add(applyCampNew);
					}
				}

			}

			// 设paymentTp
			orderNew.setPaymentTp(Orders.ORDER_PAYMENT_TYPE.MY_WALLET.getValue());
			orderNew.setPaymentSt("10");
			// 设分批出货拆单
			orderNew.setSplitType("2");
			// 设等待配货
			orderNew.setOrderSt("20");
			// 设原订单id
			orderNew.setOrgOrderId(orderSrc.getOrderId());
			// 设未同步
			orderNew.setSync(false);
			// 设不需拆单
			orderNew.setAllowSplit("N");
			orderNew.setPaymentId(null);
			orderNew.setPaymentSrc(" ");
			orderNew.setPaymentDt(new Date());
			orderNew.setOrderDt(DateUtil.getCurrentTime());

			orderNew.setMustPay(BigDecimal.ZERO);
			orderNew.setTotalPrice(__totalPrice);
			orderNew.setAmount(__amount);
			orderNew.setDiscount(__discount);
			orderNew.setCoupon(__coupon);
			orderNew.setBonus(__bonus);
			orderNew.setInstallmentFee(BigDecimal.ZERO);
			orderNew.setCash(BigDecimal.ZERO);
			orderNew.setShipfare(__shipfare);
			orderNew.setMyWallet(__myWallet);
			orderNew.setTotalWeight(__weight);
			orderNew.setGiftcardBalance(__giftcardBalance);
			if (orderSrc.getMyWalletShipfare().compareTo(BigDecimal.ZERO) == 1) {
				orderNew.setMyWalletShipfare(__shipfare);
			}
			if (orderSrc.getGiftcardBalanceShipfare().compareTo(BigDecimal.ZERO) == 1) {
				orderNew.setGiftcardBalanceShipfare(__shipfare);
			}
			orderNew.setOrderProduct(orderProdsNew);
			orderNew.setApplyCampaigns(applyCampaignsNew);
			if (!checkAmountBeforeOrder(orderNew)) {// 检查订单金额不得为负项
				throw new RuntimeException("订单金额不得为负项");
			}
			ordersNew.add(orderNew);
		}

		// 新旧order的product数要相等
		if (orderProdCnt != orderSrc.getOrderProduct().size()) {
			throw new RuntimeException("Order_Product_id数量不相等！");
		}

		// 退款 & 成立取消单
		ServiceOrders serviceOrder = serviceOrderService.cancelOrderBySystemSplit(orderSrc);

		try {

			// 成立新订单
			StringBuffer sb = new StringBuffer();
			BigDecimal tmpGiveBonus = BigDecimal.ZERO;
			BigDecimal priceSrc = orderSrc.getMustPay().subtract(orderSrc.getShipfare()).subtract(orderSrc.getCodFee()).add(
					orderSrc.getMyWallet()).add(orderSrc.getGiftcardBalance());
			BigDecimal priceNew = BigDecimal.ZERO;
			for (int i = 0; i < ordersNew.size(); i++) {
				Orders order = ordersNew.get(i);
				save(order);
				checkOrderAmountFw(order);
				if (null != obcSrc) {// 按比例分配要发送的积分(抓旧订单的积分发送资料来拆分,不再另外计算)
					OrderBonusCampaign obcNew = new OrderBonusCampaign();
					BeanUtils.copyProperties(obcSrc, obcNew, new String[] { "orderId" });
					if (i == ordersNew.size() - 1) {
						priceNew = obcSrc.getGiveBonus().subtract(tmpGiveBonus);
					} else {
						priceNew = order.getMustPay().subtract(order.getShipfare()).subtract(order.getCodFee()).add(
								order.getMyWallet()).add(order.getGiftcardBalance());
						priceNew = priceNew.divide(priceSrc, 1, RoundingMode.DOWN).multiply(obcSrc.getGiveBonus()).setScale(0,
								RoundingMode.DOWN);// 计算要发放的积分，如果divide只取到整数的话会有没分配到积分的风险，所以取到小数点第一位无条件舍去后再去乘原本要发放的积分
						tmpGiveBonus = tmpGiveBonus.add(priceNew);
					}
					obcNew.setOrderId(order.getOrderId());
					obcNew.setGiveBonus(priceNew);
					orderBonusCampaignDao.save(obcNew);
				}
				// 拆单更新资料
				order.setJoinMustPay(order.getMustPay());
				order.setJoinOrders(order.getOrderId());
				order = save(order);
				sb.append(order.getOrderId());
				if (i < (ordersNew.size() - 1)) {
					sb.append(",");
				}
				afterNewOrderOfSplit(order, order.getMyWallet(), getCpItemUUIDFromOrder(order), order.getBonus(), order
						.getGiftcardBalance());
			}

			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			orderSrc.setMemo(df.format(new Date()) + " 拆单为 " + sb.toString());
			orderSrc.setNewOrderId(sb.toString());
			baseMgr.update(orderSrc);

			serviceOrder.setDescription(df.format(new Date()) + " 拆单为 " + sb.toString());
			baseMgr.update(serviceOrder);

			Member member = (Member) baseMgr.get(Member.class, orderSrc.getMemberId());

			// Send Mail
			Map<String, Object> contentMap = new HashMap<String, Object>();
			contentMap.put("order", orderSrc);
			contentMap.put("memberName", orderSrc.getMemberName());
			contentMap.put("ordersNew", ordersNew);
			contentMap.put("contextPath", ServerValue.getFrontContextPath());
			contentMap.put("basehref", "http://" + orderSrc.getDomainSrc());
			contentMap.put("orderStMenu", menuService.get("Order.status"));

			Mail mail = velocityService.formatToMail("order.splitOrder", contentMap);
			mail.setTo(member.getEmail());
			mail.setFrom(envParameters.getEmailFromSystem());
			mailService.save(mail);

			// Send SMS
			String msg = "亲，订单" + orderSrc.getOrderId() + "将被拆分为" + ordersNew.size()
					+ "单，订单中商品将分开发货。欲了解拆单详情可登陆耀点100网站查看我的订单。";
			if (StringUtils.isNotBlank(member.getMobile())) {
				smsService.sendSms(member.getMobile(), msg, orderSrc.getOrderId());
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getLocalizedMessage() + ",System update order failed! Pay by myWallet failed.");
		}
		return "true";
	}

	private boolean validateDataInList(Object arg, List list) {
		boolean boo = false;
		if (null != list) {
			for (Object obj : list) {
				if (arg.equals(obj)) {
					boo = true;
					break;
				}
			}
		}
		return boo;
	}

	private String getCpItemUUIDFromOrder(Orders order) {
		StringBuffer uuid = new StringBuffer();
		if (order.getCoupon().intValue() > 0) {
			for (OrderProduct orderProd : order.getOrderProduct()) {
				if (orderProd.getCoupon().intValue() > 0 && StringUtils.isNotBlank(orderProd.getCouponId())
						&& StringUtils.isNotBlank(orderProd.getCouponItemId())) {
					uuid = uuid.append(orderProd.getCouponItemId()).append(",");
				}
			}
		}
		return uuid.toString();
	}

	private void afterNewOrderOfSplit(Orders orders, BigDecimal chkVrtBlnc, String cpItemUUID, BigDecimal editBonus,
			BigDecimal chkGiftCard) throws Exception {
		// 扣除帳戶餘額
		if (chkVrtBlnc.floatValue() > 0.0f) {
			VirtualBalance vb = new VirtualBalance();
			vb.setMemberId(orders.getMemberId());
			vb.setTrxDate(new Date());
			vb.setTrxType(VirtualBalanceType.EC_ORDER_MAIN.name());
			vb.setTrxAmount(chkVrtBlnc.negate());
			vb.setDescription("支付至订单：<a href=\"" + ServerValue.getFrontContextPath()
					+ "/member/order/page.do?page=detail&orderId=" + orders.getOrderId() + "\">" + orders.getOrderId() + "</a>");
			vb.setTrxTypeId(orders.getOrderId());
			vb.setType(VirtualBalancePayType.VirtualBalance.getValue());
			vb = memberService.saveOrUpdateVirtualBalance(vb);
		}
		// 扣除礼品卡余额
		if (chkGiftCard.floatValue() > 0.0f) {
			VirtualBalance vbGiftcard = new VirtualBalance();
			vbGiftcard.setMemberId(orders.getMemberId());
			vbGiftcard.setTrxDate(new Date());
			vbGiftcard.setTrxType(VirtualBalanceType.EC_ORDER_MAIN.name());
			vbGiftcard.setTrxAmount(chkGiftCard.negate());
			vbGiftcard.setDescription("支付至订单：<a href=\"" + ServerValue.getFrontContextPath()
					+ "/member/order/page.do?page=detail&orderId=" + orders.getOrderId() + "\">" + orders.getOrderId() + "</a>");
			vbGiftcard.setTrxTypeId(orders.getOrderId());
			vbGiftcard.setType(VirtualBalancePayType.GiftcardBalance.getValue());
			vbGiftcard = memberService.saveOrUpdateVirtualBalance(vbGiftcard);
		}

		// 扣除coupon
		List<OrderProduct> ops = orders.getOrderProduct();
		for (OrderProduct orderP : ops) {
			if (StringUtils.isNotBlank(orderP.getCouponItemId())) {
				couponService.forceUseCoupon(orderP.getCouponItemId(), orders.getMemberId(), orders.getOrderId());
			}
		}
		// 扣除bonus
		if (editBonus.compareTo(BigDecimal.ZERO) == 1) {
			transferService.chargeByBonusTransfer(orders);
		}
		// 扣數量
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("orderId", orders.getOrderId());
		List<OrderProductDetail> orderProductDetails = new ArrayList();
		for (OrderProduct op : orders.getOrderProduct()) {
			orderProductDetails.addAll(op.getOrderProductDetail());
		}
		int updateError = 0;
		StringBuffer updateErrorStr = new StringBuffer();
		for (OrderProductDetail orderProductDetail : orderProductDetails) {
			if (orderProductDetail.getQty() > 0 && !orderProductDetail.getProdSpecName().equals("N选M")) {
				try {
					Integer update = (Integer) baseMgr.executeHql(
							"update SpecificationInventory a set a.modifyDate=sysdate, a.soldInventory = a.soldInventory + ? "
									+ " where (availableInventory + cancelInventory - soldInventory) >= ?"
									+ " and a.productId = ? and specId = ? ", new Object[] { orderProductDetail.getQty(),
									orderProductDetail.getQty(), orderProductDetail.getProdId(),
									Long.parseLong(orderProductDetail.getProdSpecId()) });
					// logService.save(getClass().getSimpleName(), "afterOrders-specInv", specificationInventory);
					if (update == 0) {
						updateError++;
						updateErrorStr.append("商品编号:" + orderProductDetail.getProdId() + "(" + orderProductDetail.getProdName()
								+ "), 规格编号:" + orderProductDetail.getProdSpecId() + "(" + orderProductDetail.getProdSpecName() + "):"
								+ "数量不足！！");
					}
				} catch (Exception ee) {
					throw new CoreException(orderProductDetail.getProdId() + ":" + orderProductDetail.getProdSpecId() + ":"
							+ "数量更新异常，无法成立部份取消订单！！");
				}
			}
		}
	}

	@Transactional(readOnly = false)
	public Orders reCalcBonusAndGiftcardAndMyWallet(Orders order) {
		if (order.getGiftcardBalance().floatValue() > 0) {
			// 禮品卡 - 商品總額 - 折扣 - 积分 > 0 ，才去計算禮品卡運費
			BigDecimal giftcardBalancePaidProd = order.getGiftcardBalance().subtract(order.getAmount()).subtract(
					order.getBonus());
			if (giftcardBalancePaidProd.compareTo(BigDecimal.ZERO) == 1) {
				if (order.getMyWallet().floatValue() < (order.getShipfare().floatValue() + order.getCodFee().floatValue())) {// 帳戶餘額<運費+cod手續費,用禮品卡支付運費，再攤提到各商品
					BigDecimal tmpGiftcardShipfare = order.getMyWallet().subtract(order.getShipfare())
							.subtract(order.getCodFee()).abs();// 帳戶餘額-運費-COD手續費=剩於要用禮品卡支付的運費
					if (giftcardBalancePaidProd.floatValue() <= tmpGiftcardShipfare.floatValue()) {// 禮品卡額額<= 剩於要支付的運費
						order.setGiftcardBalanceShipfare(giftcardBalancePaidProd);// 禮品卡運費=禮品卡餘額
					} else {
						order.setGiftcardBalanceShipfare(tmpGiftcardShipfare);
					}
				} else {
					order.setGiftcardBalanceShipfare(BigDecimal.ZERO);
				}
			}
			BigDecimal tmpgb = order.getGiftcardBalance().subtract(order.getGiftcardBalanceShipfare());// 禮品卡-禮品卡支付運費
			if (tmpgb.compareTo(BigDecimal.ZERO) == 1) {// 禮品卡-禮品卡支付運費大於0
				int i = 0;
				BigDecimal tmpTotalGiftcardBalance = BigDecimal.ZERO;
				CommonCriteria crit = new CommonCriteria();
				crit.addEq("orderId", order.getOrderId());
				List<OrderProductDetail> details = getOrderProdDetailList(0, -1, crit, new String[] { "prodSeq asc" });
				for (OrderProductDetail detail : details) {
					if (details.size() == 1) {
						detail.setGiftcardBalance(tmpgb);
					} else {
						if (i < details.size() - 1) {
							detail.setGiftcardBalance(detail.getAmount().multiply(tmpgb).divide(order.getTotalPrice(), 1,
									RoundingMode.DOWN));
							tmpTotalGiftcardBalance = tmpTotalGiftcardBalance.add(detail.getGiftcardBalance());
						} else {
							detail.setGiftcardBalance(tmpgb.subtract(tmpTotalGiftcardBalance));
						}
						i++;
					}
				}
			}
		}
		return order;
	}

	// 商品已 送达, 发送积分
	private void giveOrderBonus(Orders order) {
		if (order.getBonusSendDate() != null) {
			// 已发送过
			return;
		}
		OrderBonusCampaign obCampaign = order.getOrderBonusCampaign();
		if (null != obCampaign && (obCampaign.getGiveBonus().compareTo(new BigDecimal("0")) == 1)) {
			Bonus bonus = new Bonus();
			bonus.setMemberId(order.getMemberId());
			bonus.setOrderId(order.getOrderId());
			bonus.setTrxAmount(obCampaign.getGiveBonus());
			bonus.setTrxType("ORDER_BONUS");
			bonus.setTrxDate(new Date());
			bonus.setDescription(obCampaign.getCampaignName());
			try {
				DateFormat df = new SimpleDateFormat("yyyyMMdd");
				bonus.setStartDate(df.parse(df.format(DateUtils.addDays(new Date(), Integer.parseInt(obCampaign
						.getStartPeriod())))));
				Date expireDate = df.parse(new SimpleDateFormat("yyyyMM").format(DateUtils.addMonths(bonus.getStartDate(),
						Integer.parseInt(obCampaign.getPeriodDays()) + 1))
						+ "01");
				bonus.setExpireDate(new Date(expireDate.getTime() - 1));
				bonus = memberService.saveOrUpdateBonus(bonus);

				// 设定为已发送
				order.setBonusSendDate(bonus.getTrxDate());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public Orders updateProduct(String orderId, Long specId, int qty, BigDecimal price, boolean modifyInventory,
			String prodName, String specName, BigDecimal discount) throws CoreException {
		return updateOuterProduct(orderId, specId, qty, price, modifyInventory, prodName, specName, discount, null, null,
				null);
	}

	@Transactional(readOnly = false)
	public Orders updateOuterProduct(String orderId, Long specId, int qty, BigDecimal price, boolean modifyInventory,
			String prodName, String specName, BigDecimal discount, String outerCid, String outerProdId, String outerSkuId)
			throws CoreException {
		Orders order = get(orderId);
		if (order.isSync()) {
			return order;
		}
		OrderProduct op = null;
		for (OrderProduct oop : order.getOrderProduct()) {
			if (oop.getProdSpecId().equals(specId.toString())) {
				op = oop;
				break;
			}
		}
		if (op == null) {
			Specification spec = productService.getSpecification(specId);
			Product prod = null;
			// TODO
			if (spec == null) {
				spec = new Specification();
				spec.setSpecificationId(specId);
				spec.setSpecificationName(specName);
				prod = new Product();
				prod.setProductId("00000001");
				prod.setProductName(prodName);
				prod.setMainCategoryPath("7");
			} else {
				prod = productService.get(spec.getProductId());
			}

			if (modifyInventory) {
				SpecificationInventory si = productService.getSpecificationInventory(spec.getProductId(), specId);
				si.setSoldInventory(si.getSoldInventory() + qty);
				productService.saveSpecificationInventory(si);
			}
			Shelf shelf = new Shelf();
			shelf.setShelfPrice(price);
			op = new OrderProduct(prod, spec, prod.getMainCategoryPath(), shelf);
			op.setProdName(prodName);
			op.setProdSpecName(specName);
			if (discount != null) {
				op.setDiscount(discount);
			}
			OrderProductDetail opd = new OrderProductDetail(prod, spec, shelf);
			if (StringUtils.isNotBlank(prodName)) {
				opd.setProdName(prodName);
			}
			if (StringUtils.isNotBlank(specName)) {
				opd.setProdSpecName(specName);
			}
			opd.setOuterCid(outerCid);
			opd.setOuterProdId(outerProdId);
			opd.setOuterSkuId(outerSkuId);
			order.addProduct(op);
			op.addDetail(opd);
		} else {
			if (op.getQty() != qty || !op.getUnitPrice().equals(price)) {
				if (modifyInventory && (op.getQty() != qty)) {
					SpecificationInventory si = productService.getSpecificationInventory(op.getProdId(), Long.valueOf(op
							.getProdSpecId()));
					si.setSoldInventory(si.getSoldInventory() - op.getQty() + qty);
					productService.saveSpecificationInventory(si);
				}

				op.setQty(qty);
				op.setUnitPrice(price);
				op.setTotalPrice(price.multiply(BigDecimal.valueOf(qty)));
				if (discount != null) {
					op.setDiscount(discount);
				}

				for (OrderProductDetail opd : op.getOrderProductDetail()) {
					if (opd.getProdSpecId().equals(op.getProdSpecId())) {
						opd.setQty(qty);
						opd.setUnitPrice(price);
						opd.setAmount(price.multiply(BigDecimal.valueOf(qty)));
					}
				}
			}
		}
		save(order);
		return order;
	}

	@Transactional(readOnly = false)
	public Orders addOuterProduct(String orderId, Long specId, int qty, BigDecimal price, boolean modifyInventory,
			String prodName, String specName, BigDecimal discount, String outerCid, String outerProdId, String outerSkuId)
			throws CoreException {
		Orders order = get(orderId);
		if (order.isSync()) {
			return order;
		}
		OrderProduct op = null;

		if (op == null) {
			Specification spec = productService.getSpecification(specId);
			Product prod = null;
			// TODO
			if (spec == null) {
				spec = new Specification();
				spec.setSpecificationId(specId);
				spec.setSpecificationName(specName);
				prod = new Product();
				prod.setProductId("00000001");
				prod.setProductName(prodName);
				prod.setMainCategoryPath("7");
			} else {
				prod = productService.get(spec.getProductId());
			}

			if (modifyInventory) {
				SpecificationInventory si = productService.getSpecificationInventory(spec.getProductId(), specId);
				si.setSoldInventory(si.getSoldInventory() + qty);
				productService.saveSpecificationInventory(si);
			}
			Shelf shelf = new Shelf();
			shelf.setShelfPrice(price);
			op = new OrderProduct(prod, spec, prod.getMainCategoryPath(), shelf);
			op.setProdName(prodName);
			op.setProdSpecName(specName);
			if (discount != null) {
				op.setDiscount(discount);
			}
			OrderProductDetail opd = new OrderProductDetail(prod, spec, shelf);
			if (StringUtils.isNotBlank(prodName)) {
				opd.setProdName(prodName);
			}
			if (StringUtils.isNotBlank(specName)) {
				opd.setProdSpecName(specName);
			}
			opd.setOuterCid(outerCid);
			opd.setOuterProdId(outerProdId);
			opd.setOuterSkuId(outerSkuId);
			order.addProduct(op);
			op.addDetail(opd);
		}
		save(order);
		return order;
	}

	/**
	 * 订单金额检核(有异常就写一笔memo，发mail, 并写入flag)
	 * 
	 * @param order
	 * @return
	 */
	@Transactional(readOnly = false)
	void checkOrderAmountFw(Orders order) {
		BigDecimal detailAmount = BigDecimal.ZERO;
		BigDecimal productAmount = BigDecimal.ZERO;
		BigDecimal productTotalPrice = BigDecimal.ZERO;
		List<OrderProduct> ops = order.getOrderProduct();
		StringBuffer order_error = new StringBuffer();
		// 外部商城訂單允許到小數點二位數
		int dot = 1;
		if ("3".equals(order.getOrderType())) {
			dot = 2;
		}
		for (OrderProduct op : ops) {
			for (OrderProductDetail opd : op.getOrderProductDetail()) {
				detailAmount = detailAmount.add(opd.getAmount()).setScale(dot, RoundingMode.CEILING);
			}
			productAmount = productAmount.add(op.getAmount()).setScale(dot, RoundingMode.CEILING);
			productTotalPrice = productTotalPrice.add(op.getTotalPrice()).setScale(dot, RoundingMode.CEILING);
		}
		// 訂單主檔.total_price <> sum(訂單明細 amount)
		BigDecimal totalPrice = order.getTotalPrice().setScale(dot, RoundingMode.CEILING);
		BigDecimal amount = order.getAmount().setScale(dot, RoundingMode.CEILING);
		if (totalPrice.floatValue() != detailAmount.floatValue()) {
			order_error = order_error.append(order_amount_error1).append(",").append(totalPrice).append(" != ").append(
					detailAmount).append("<br>");
		}
		// 訂單主檔.total_price <> sum(訂單商品.total_price)
		if (totalPrice.floatValue() != productTotalPrice.floatValue()) {
			order_error = order_error.append(order_amount_error2).append(",").append(totalPrice).append(" != ").append(
					productTotalPrice).append("<br>");
		}
		// sum(訂單商品.amount) <> 訂單主檔.amount
		if (amount.floatValue() != productAmount.floatValue()) {
			order_error = order_error.append(order_amount_error3).append(",").append(amount).append(" != ").append(
					productAmount).append("<br>");
		}
		// 訂單主檔.must_pay + 訂單主檔.my_wallet + 訂單主檔.bonus +訂單主檔.giftcard_balance <>
		// 訂單主檔.amount + 訂單主檔.shipfare + 訂單主檔.cod_fee + 訂單主檔.installment_fee
		BigDecimal o1 = order.getMustPay().add(order.getMyWallet()).add(order.getBonus()).add(order.getGiftcardBalance())
				.setScale(dot, RoundingMode.CEILING);
		BigDecimal o2 = order.getAmount().add(order.getShipfare()).add(order.getCodFee()).add(order.getInstallmentFee())
				.setScale(dot, RoundingMode.CEILING);
		if (o1.floatValue() != o2.floatValue()) {
			order_error = order_error.append(order_amount_error4).append(",").append(o1).append(" != ").append(o2).append(
					"<br>");
		}
		if (order_error.length() > 0) {
			logger.error("detailAmount:{}", detailAmount);
			logger.error("productAmount:{}", productAmount);
			logger.error("productTotalPrice:{}", productTotalPrice);
			logger.error("totalPrice:{}", totalPrice);
			logger.error("amount:{}", amount);
			systemValueMenu = menuService.get("SystemValue");
			String fwOrderAmountEnable = systemValueMenu.getOptions().get("fw_order_amount_enable").getMemo1();
			if (StringUtils.equalsIgnoreCase("on", fwOrderAmountEnable)) {
				throw new CoreException("金额异常＠" + "订单编号：" + order.getOrderId() + "成立失败＠" + order_error.toString() + "金额异常");
			} else {
				order.setExceptionFlag("Y");
				update(order);
				// 新增一筆至memo
				OrderMemo orderMemo = new OrderMemo();
				orderMemo.setOrderId(order.getOrderId());
				orderMemo.setMemo(order_error.toString());
				saveOrderMemo(orderMemo);
				order_error.setLength(0);
				// send mail to frontend
				Mail mail = new Mail("订单编号：" + orderMemo.getOrderId() + "金额异常", orderMemo.getMemo() + "金额异常",
						"fe@yaodian100.com", "");
				mail.setFrom(envParameters.getEmailFromSystem());
				mailService.save(mail);
			}
		}
	}

	/**
	 * 成立订单前的金额检查
	 * 
	 * @param order
	 * @return
	 */
	boolean checkAmountBeforeOrder(Orders order) {
		if (order.getAmount().floatValue() < 0 || order.getShipfare().floatValue() < 0
				|| order.getCodFee().floatValue() < 0 || order.getDiscount().floatValue() < 0
				|| order.getCoupon().floatValue() < 0 || order.getBonus().floatValue() < 0
				|| order.getGiftcardBalance().floatValue() < 0 || order.getMyWallet().floatValue() < 0
				|| order.getInstallmentFee().floatValue() < 0) {
			logger.error("檢核成立訂單時的amount不得小於零:{}", order.getAmount());
			logger.error("檢核成立訂單時的Shipfare不得小於零:{}", order.getShipfare());
			logger.error("檢核成立訂單時的CodFee不得小於零:{}", order.getCodFee());
			logger.error("檢核成立訂單時的Discount不得小於零:{}", order.getDiscount());
			logger.error("檢核成立訂單時的Coupon不得小於零:{}", order.getCoupon());
			logger.error("檢核成立訂單時的Bonus不得小於零:{}", order.getBonus());
			logger.error("檢核成立訂單時的GiftcardBalance不得小於零:{}", order.getGiftcardBalance());
			logger.error("檢核成立訂單時的MyWallet不得小於零:{}", order.getMyWallet());
			logger.error("檢核成立訂單時的InstallmentFee不得小於零:{}", order.getInstallmentFee());
			return false;
		}
		if (order.getAmount().add(order.getShipfare()).add(order.getCodFee()).compareTo(BigDecimal.ZERO) < 0) {
			logger.error("訂單金額警示: order:" + order + ",amount+shipfare+codfee:"
					+ order.getAmount().add(order.getShipfare()).add(order.getCodFee()));
			return false;
		}
		if (null != order.getOrderProduct()) {
			int err = 0;
			for (OrderProduct op : order.getOrderProduct()) {
				if (op.getAmount().floatValue() < 0 || op.getShipfare().floatValue() < 0 || op.getCodFee().floatValue() < 0
						|| op.getDiscount().floatValue() < 0 || op.getCoupon().floatValue() < 0 || op.getBonus().floatValue() < 0
						|| op.getGiftcardBalance().floatValue() < 0 || op.getMyWallet().floatValue() < 0
						|| op.getInstallmentFee().floatValue() < 0) {
					err = err++;
				}
				if (err == 0) {
					if (null != op.getOrderProductDetail()) {
						for (OrderProductDetail opd : op.getOrderProductDetail()) {
							if (opd.getAmount().floatValue() < 0 || opd.getShipfare().floatValue() < 0
									|| opd.getCodFee().floatValue() < 0 || opd.getDiscount().floatValue() < 0
									|| opd.getCoupon().floatValue() < 0 || opd.getBonus().floatValue() < 0
									|| opd.getGiftcardBalance().floatValue() < 0 || opd.getMyWallet().floatValue() < 0
									|| opd.getInstallmentFee().floatValue() < 0) {
								err = err++;
							}
						}
					}
				}
			}
			if (err != 0) {
				return false;
			}
		}
		return true;
	}

	private void checkAddress(Orders order) {
		if (order.getReceiverAddr() == null || order.getReceiverArea() == null || order.getReceiverCity() == null
				|| order.getReceiverProvince() == null || order.getReceiverZip() == null) {
			for (int i = 0; i < 100; i++) {
				logger.error("province, city, area, addr, zip not allow to null!!! outerOrderId:" + order.getOuterOrderId());
			}
			throw new RuntimeException("province, city, area, addr or zip are null!outerOrderId:" + order.getOuterOrderId());
		}
	}

	@Override
	@Transactional(readOnly = false)
	public Orders save(Orders entity) throws CoreException {
		// 地址未填，不允许产生订单！！
		checkAddress(entity);
		Orders order = super.save(entity);
		if (!"3".equals(order.getOrderType())) {// 外部商城订单因写法不同，因此在存檔时先不检核金额
			checkOrderAmountFw(order);// 订单金额检核(有异常就写一笔memo，发mail, 并写入flag)
		}
		return order;
	}

	BigDecimal calcGiveBonus(Orders order) {
		return calcGiveBonus(order, null);

	}

	public BigDecimal calcGiveBonus(Orders order, String giveBonusSetting) {
		BigDecimal giveBonus = BigDecimal.ZERO;
		try {
			BigDecimal price = order.getMustPay().subtract(order.getShipfare()).subtract(order.getCodFee()).subtract(
					order.getInstallmentFee()).add(order.getMyWallet()).add(order.getGiftcardBalance());
			if (StringUtils.isBlank(giveBonusSetting)) {
				giveBonusSetting = order.getOrderBonusCampaign().getGiveBonusSetting();
			}
			if (price.compareTo(BigDecimal.ZERO) == 1 && StringUtils.isNotBlank(giveBonusSetting)) {
				BigDecimal minOrderAmount = BigDecimal.ZERO;
				BigDecimal maxOrderAmount = BigDecimal.ZERO;
				BigDecimal minQty = BigDecimal.ZERO;
				BigDecimal maxQty = BigDecimal.ZERO;
				boolean isUpperLimit = false;
				BigDecimal bonusLimit = BigDecimal.ZERO;
				JSONObject jaObj = null;
				JSONArray bonusJA = new JSONArray(giveBonusSetting);
				if (null != bonusJA) {
					for (int i = 0; i < bonusJA.length(); i++) {
						jaObj = bonusJA.getJSONObject(i);
						minOrderAmount = new BigDecimal(jaObj.get("minOrderAmount").toString());
						maxOrderAmount = new BigDecimal(jaObj.get("maxOrderAmount").toString());
						minQty = new BigDecimal(jaObj.get("minQty").toString());
						maxQty = new BigDecimal(jaObj.get("maxQty").toString());
						isUpperLimit = "false".equals(jaObj.get("isUpperLimit").toString()) ? false : true;
						if (minOrderAmount.floatValue() <= price.floatValue() && maxOrderAmount.floatValue() >= price.floatValue()) {
							giveBonus = price.divide(minQty, 0, RoundingMode.DOWN).multiply(maxQty);// 无条件舍去
							if (isUpperLimit) {// 有設定封頂,則用封頂上限
								bonusLimit = new BigDecimal(jaObj.get("bonusLimit").toString());
								if (giveBonus.compareTo(bonusLimit) == 1) {
									giveBonus = bonusLimit;
								}
							}
						}
					}
				}
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return giveBonus;
	}

	public BigDecimal calcOffsetBonus(String domainSrc, String cookie, Balance balance, BigDecimal orderAmount) {
		BigDecimal iOffset = BigDecimal.ZERO;
		// 会员积分檢查
		Map<String, String> optional = new HashMap<String, String>();
		optional.put("domain", domainSrc);
		optional.put("cookie", cookie);
		Campaign bc = campaignService.getActiveBonusCampaignByM02(optional);
		if (null != bc) {
			BigDecimal perc = new BigDecimal(bc.getOffsetUpperLimit()).divide(BigDecimal.valueOf(100));
			// 订单金额折抵上限
			iOffset = orderAmount.multiply(perc).setScale(0, RoundingMode.UP);
			// 将积分转换为钱(无条件舍去，避免小于折抵的积分也可以折抵)
			BigDecimal bonusPrice = (balance.getBonusBalance().divide(new BigDecimal(bc.getOffsetRate())).setScale(0,
					RoundingMode.DOWN));
			// 订单折抵上限>可用的积分
			if (iOffset.compareTo(bonusPrice) == 1) {
				iOffset = bonusPrice;
			}
			// 订单最多可折抵积分
			if (iOffset.compareTo(new BigDecimal(bc.getOffsetDiscountLimit())) == 1) {
				iOffset = new BigDecimal(bc.getOffsetDiscountLimit());
			}
		}
		return iOffset;
	}

	@Transactional(readOnly = false)
	public OrderBonusCampaign saveOrderBonusSetting(Orders order, BigDecimal offsetRate, BigDecimal offsetUpperLimit,
			BigDecimal offsetDiscountLimit) {
		Map<String, String> optional = new HashMap<String, String>();
		optional.put("domain", order.getDomainSrc());
		optional.put("cookie", order.getChannel());
		// 取得会员积分发送规则
		Campaign gcp = campaignService.getActiveBonusCampaignByM01(optional);
		OrderBonusCampaign obc = new OrderBonusCampaign();
		if (null != gcp) {
			try {
				JSONArray settingArray = new JSONArray();
				JSONObject settingObj = null;
				for (CampaignExtend ext : gcp.getTypeExtends()) {
					settingObj = new JSONObject();
					settingObj.put("minOrderAmount", ext.getMinOrderAmount().toString());
					settingObj.put("maxOrderAmount", ext.getMaxOrderAmount().toString());
					settingObj.put("minQty", ext.getMinQty());
					settingObj.put("maxQty", ext.getMaxQty());
					settingObj.put("isUpperLimit", ext.isUpperLimit());
					settingObj.put("bonusLimit", ext.getBonusLimit());
					settingArray.put(settingObj);
				}
				obc.setOrderId(order.getOrderId());
				obc.setOffsetRate(offsetRate);
				obc.setOffsetUpperLimit(offsetUpperLimit);
				obc.setOffsetDiscountLimit(offsetDiscountLimit);
				obc.setGiveBonusSetting(settingArray.toString());
				obc.setCampaignName(gcp.getCampaignName());
				obc.setGiveBonus(calcGiveBonus(order, obc.getGiveBonusSetting()));
				obc.setPeriodDays(gcp.getPeriodDays());
				obc.setStartPeriod(gcp.getStartPeriod());
				orderBonusCampaignDao.save(obc);
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return obc;
	}

	/**
	 * 第三方支付收款时，原订单分配的mustpay=cash
	 * 
	 * @param order
	 * @return
	 */
	@Transactional(readOnly = false)
	public Orders calcOrderCash(Orders order) {
		if (null == order.getOrderProduct() || order.getOrderProduct().size() == 0) {
			order = get(order.getOrderId());
		}
		if (StringUtils.isBlank(order.getTranslateFlag())) {
			order.setTranslateFlag("Y");
		}
		for (OrderProduct op : order.getOrderProduct()) {
			op.setCash(op.getMustPay());
			for (OrderProductDetail opd : op.getOrderProductDetail()) {
				opd.setCash(opd.getMustPay());
			}
		}
		return order;
	}

	/**
	 * 计算商品的礼品卡、账户余额、积分、运费、cod手续费、分期手续费、mustpay摊提费用比例
	 * 
	 * @param order
	 */
	@Transactional(readOnly = false)
	public Orders calcOrderProduct(Orders order) {
		if (order.getGiftcardBalance().add(order.getMyWallet()).compareTo(BigDecimal.ZERO) == 1) {
			// 禮品卡 + 帳戶餘額 - order.amount - 积分 > 0 ，才去計算禮品卡、帳戶餘額攤提運費
			BigDecimal paidProd = order.getMyWallet().add(order.getGiftcardBalance()).subtract(
					order.getAmount().subtract(order.getBonus()));
			if (paidProd.compareTo(BigDecimal.ZERO) == 1) {
				// 总共要支付的费用(shipfare+codfee+install-mustpay)
				BigDecimal totalPaidAmount = order.getShipfare().add(order.getCodFee()).add(order.getInstallmentFee())
						.subtract(order.getMustPay());
				if (totalPaidAmount.compareTo(BigDecimal.ZERO) == 1) {
					if (order.getGiftcardBalance().compareTo(totalPaidAmount) == -1) {// 礼品卡金额<支付费用
						if (order.getMyWallet().compareTo(totalPaidAmount) == 1) {// 账户余额<支付费用
							order.setMyWalletShipfare(totalPaidAmount);
						}
					} else {
						order.setGiftcardBalanceShipfare(totalPaidAmount);
					}
				}
			}
		}
		order.setTranslateFlag("Y");
		// BigDecimal tmpGiftCard = order.getGiftcardBalance().subtract(order.getGiftcardBalanceShipfare());// 礼品卡-礼品卡支付运费
		// BigDecimal tmpMyWallet = order.getMyWallet().subtract(order.getMyWalletShipfare());// 账户余额-账户余额支付运费
		BigDecimal tmpGiftCard = order.getGiftcardBalance();// 礼品卡
		BigDecimal tmpMyWallet = order.getMyWallet();// 账户余额
		int i = 0, j = 0;
		List<String> opDiscountTypes = Arrays.asList("0", "1", "3", "6", "7");// 可享有折扣的商品型态为一般、预购、加购、nm、精品
		List<String> opCouponTypes = Arrays.asList("0", "1", "6", "7");// 可享有coupon的商品型态为一般、预购、nm、精品
		BigDecimal remainderProdShipfare = BigDecimal.ZERO;
		BigDecimal remainderProdCodFee = BigDecimal.ZERO;
		BigDecimal remainderProdInstallmentFee = BigDecimal.ZERO;
		BigDecimal remainderProdMustPay = BigDecimal.ZERO;
		BigDecimal remainderProdGiftcardBalance = BigDecimal.ZERO;
		BigDecimal remainderProdMywallet = BigDecimal.ZERO;
		BigDecimal remainderProdBonus = BigDecimal.ZERO;
		BigDecimal remainderDetailShipfare = BigDecimal.ZERO;
		BigDecimal remainderDetailCodFee = BigDecimal.ZERO;
		BigDecimal remainderDetailInstallmentFee = BigDecimal.ZERO;
		BigDecimal remainderDetailMustPay = BigDecimal.ZERO;
		BigDecimal remainderDetailGiftcardBalance = BigDecimal.ZERO;
		BigDecimal remainderDetailMywallet = BigDecimal.ZERO;
		BigDecimal remainderDetailBonus = BigDecimal.ZERO;
		BigDecimal remainderDetailCoupon = BigDecimal.ZERO;
		BigDecimal remainderDetailDiscount = BigDecimal.ZERO;
		BigDecimal orderProdPay = BigDecimal.ZERO;
		BigDecimal orderDetailPay = BigDecimal.ZERO;
		BigDecimal _bonus = BigDecimal.ZERO;
		BigDecimal _shipfare = BigDecimal.ZERO;
		BigDecimal _codfee = BigDecimal.ZERO;
		BigDecimal _installment = BigDecimal.ZERO;
		BigDecimal _giftcard = BigDecimal.ZERO;
		BigDecimal _myWallet = BigDecimal.ZERO;
		BigDecimal _mustPay = BigDecimal.ZERO;
		BigDecimal _discount = BigDecimal.ZERO;
		BigDecimal _coupon = BigDecimal.ZERO;
		BigDecimal orderPay = order.getAmount().subtract(order.getBonus());
		// 贈品不列入計算,因积分的比例分配问题，避免最后一单的金额很小，却分配到剩余积分，所以依金额由小到大排序
		List<OrderProduct> ops = orderProdFilter(order);
		// 外部商城訂單允許到小數點二位數
		int dot = 1;
		if ("3".equals(order.getOrderType())) {
			dot = 2;
		}
		if (null != ops && ops.size() > 0) {
			for (OrderProduct op : ops) {
				if (i < ops.size() - 1) {
					if (order.getBonus().compareTo(BigDecimal.ZERO) == 1) {
						_bonus = order.getBonus().multiply(op.getTotalPrice().subtract(op.getDiscount())).divide(
								order.getTotalPrice().subtract(order.getDiscount()), dot, BigDecimal.ROUND_CEILING);
						remainderProdBonus = remainderProdBonus.add(_bonus);
						if (remainderProdBonus.compareTo(order.getBonus()) == 1) {
							remainderProdBonus = remainderProdBonus.subtract(_bonus);
							_bonus = order.getBonus().subtract(remainderProdBonus);
							remainderProdBonus = order.getBonus();
						}
						op.setBonus(_bonus);
					} else {
						op.setBonus(BigDecimal.ZERO);
					}
					orderProdPay = op.getAmount().subtract(op.getBonus());
					if (orderProdPay.compareTo(BigDecimal.ZERO) == 0) {// 避免除数为0
						orderProdPay = new BigDecimal("1");
					}
					if (order.getShipfare().compareTo(BigDecimal.ZERO) == 1) {
						_shipfare = order.getShipfare().multiply(orderProdPay).divide(orderPay, dot, BigDecimal.ROUND_CEILING);
						remainderProdShipfare = remainderProdShipfare.add(_shipfare);
						if (remainderProdShipfare.compareTo(order.getShipfare()) == 1) {
							remainderProdShipfare = remainderProdShipfare.subtract(_shipfare);
							_shipfare = order.getShipfare().subtract(remainderProdShipfare);
							remainderProdShipfare = order.getShipfare();
						}
						op.setShipfare(_shipfare);
					} else {
						op.setShipfare(BigDecimal.ZERO);
					}
					if (order.getCodFee().compareTo(BigDecimal.ZERO) == 1) {
						_codfee = order.getCodFee().multiply(orderProdPay).divide(orderPay, dot, BigDecimal.ROUND_CEILING);
						remainderProdCodFee = remainderProdCodFee.add(_codfee);
						if (remainderProdCodFee.compareTo(order.getCodFee()) == 1) {
							remainderProdCodFee = remainderProdCodFee.subtract(_codfee);
							_codfee = order.getCodFee().subtract(remainderProdCodFee);
							remainderProdCodFee = order.getCodFee();
						}
						op.setCodFee(_codfee);
					} else {
						op.setCodFee(BigDecimal.ZERO);
					}
					if (order.getInstallmentFee().compareTo(BigDecimal.ZERO) == 1) {
						_installment = order.getInstallmentFee().multiply(orderProdPay).divide(orderPay, dot,
								BigDecimal.ROUND_CEILING);
						remainderProdInstallmentFee = remainderProdInstallmentFee.add(_installment);
						if (remainderProdInstallmentFee.compareTo(order.getInstallmentFee()) == 1) {
							remainderProdInstallmentFee = remainderProdInstallmentFee.subtract(_installment);
							_installment = order.getInstallmentFee().subtract(remainderProdInstallmentFee);
							remainderProdInstallmentFee = order.getInstallmentFee();
						}
						op.setInstallmentFee(_installment);
					} else {
						op.setInstallmentFee(BigDecimal.ZERO);
					}

					if (order.getMustPay().compareTo(BigDecimal.ZERO) == 1) {
						if ((order.getMyWallet().compareTo(BigDecimal.ZERO) == 0 && order.getGiftcardBalance().compareTo(
								BigDecimal.ZERO) == 0)
								|| (order.getMyWallet().compareTo(remainderProdMywallet) == 0 && order.getGiftcardBalance().compareTo(
										remainderProdGiftcardBalance) == 0)) {
							_mustPay = op.getAmount().subtract(op.getBonus()).add(op.getShipfare()).add(op.getCodFee()).add(
									op.getInstallmentFee());
						} else {
							_mustPay = order.getMustPay().multiply(orderProdPay).divide(orderPay, dot, BigDecimal.ROUND_CEILING);
						}
						remainderProdMustPay = remainderProdMustPay.add(_mustPay);
						if (remainderProdMustPay.compareTo(order.getMustPay()) == 1) {
							remainderProdMustPay = remainderProdMustPay.subtract(_mustPay);
							_mustPay = order.getMustPay().subtract(remainderProdMustPay);
							remainderProdMustPay = order.getMustPay();
						}
						op.setMustPay(_mustPay);
					} else {
						op.setMustPay(BigDecimal.ZERO);
					}

					if (order.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 1
							&& order.getMyWallet().compareTo(BigDecimal.ZERO) == 0) {// 使用礼品卡不使用账户余额支付
						_giftcard = op.getAmount().subtract(op.getBonus()).subtract(op.getMustPay()).subtract(op.getMyWallet())
								.add(op.getShipfare()).add(op.getCodFee()).add(op.getInstallmentFee());
						remainderProdGiftcardBalance = remainderProdGiftcardBalance.add(_giftcard);
						if (remainderProdGiftcardBalance.compareTo(tmpGiftCard) == 1) {
							remainderProdGiftcardBalance = remainderProdGiftcardBalance.subtract(_giftcard);
							_giftcard = tmpGiftCard.subtract(remainderProdGiftcardBalance);
							remainderProdGiftcardBalance = tmpGiftCard;
						}
						op.setGiftcardBalance(_giftcard);
					} else {
						op.setGiftcardBalance(BigDecimal.ZERO);
					}
					if (order.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 0
							&& order.getMyWallet().compareTo(BigDecimal.ZERO) == 1) {// 使用账户余额不使用礼品卡支付
						_myWallet = op.getAmount().subtract(op.getBonus()).subtract(op.getMustPay()).add(op.getShipfare()).add(
								op.getCodFee()).add(op.getInstallmentFee());
						remainderProdMywallet = remainderProdMywallet.add(_myWallet);
						if (remainderProdMywallet.compareTo(tmpMyWallet) == 1) {
							remainderProdMywallet = remainderProdMywallet.subtract(_myWallet);
							_myWallet = tmpMyWallet.subtract(remainderProdMywallet);
							remainderProdMywallet = tmpMyWallet;
						}
						op.setMyWallet(_myWallet);
					} else {
						op.setMyWallet(BigDecimal.ZERO);
					}
					if (order.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 1
							&& order.getMyWallet().compareTo(BigDecimal.ZERO) == 1) {// 使用礼品卡和账户余额支付
						_myWallet = tmpMyWallet.multiply(orderProdPay).divide(orderPay, dot, BigDecimal.ROUND_CEILING);
						remainderProdMywallet = remainderProdMywallet.add(_myWallet);
						if (remainderProdMywallet.compareTo(tmpMyWallet) == 1) {
							remainderProdMywallet = remainderProdMywallet.subtract(_myWallet);
							_myWallet = tmpMyWallet.subtract(remainderProdMywallet);
							remainderProdMywallet = tmpMyWallet;
						}
						op.setMyWallet(_myWallet);
						_giftcard = op.getAmount().subtract(op.getBonus()).subtract(op.getMustPay()).subtract(op.getMyWallet())
								.add(op.getShipfare()).add(op.getCodFee()).add(op.getInstallmentFee());
						remainderProdGiftcardBalance = remainderProdGiftcardBalance.add(_giftcard);
						if (remainderProdGiftcardBalance.compareTo(tmpGiftCard) == 1) {
							remainderProdGiftcardBalance = remainderProdGiftcardBalance.subtract(_giftcard);
							_giftcard = tmpGiftCard.subtract(remainderProdGiftcardBalance);
							remainderProdGiftcardBalance = tmpGiftCard;
						}
						op.setGiftcardBalance(_giftcard);
					}
				} else {
					op.setGiftcardBalance(tmpGiftCard.subtract(remainderProdGiftcardBalance));
					op.setMyWallet(tmpMyWallet.subtract(remainderProdMywallet));
					op.setBonus(order.getBonus().subtract(remainderProdBonus));
					op.setMustPay(order.getMustPay().subtract(remainderProdMustPay));
					op.setShipfare(order.getShipfare().subtract(remainderProdShipfare));
					op.setCodFee(order.getCodFee().subtract(remainderProdCodFee));
					op.setInstallmentFee(order.getInstallmentFee().subtract(remainderProdInstallmentFee));
				}
				i++;
				// 贈品不列入計算,因积分的比例分配问题，避免最后一单的金额很小，却分配到剩余积分，所以依金额由小到大排序
				List<OrderProductDetail> opds = orderProdDetailFilter(op);
				remainderDetailShipfare = BigDecimal.ZERO;
				remainderDetailCodFee = BigDecimal.ZERO;
				remainderDetailInstallmentFee = BigDecimal.ZERO;
				remainderDetailMustPay = BigDecimal.ZERO;
				remainderDetailGiftcardBalance = BigDecimal.ZERO;
				remainderDetailMywallet = BigDecimal.ZERO;
				remainderDetailBonus = BigDecimal.ZERO;
				remainderDetailCoupon = BigDecimal.ZERO;
				remainderDetailDiscount = BigDecimal.ZERO;
				j = 0;
				orderProdPay = op.getAmount().subtract(op.getBonus());
				if (orderProdPay.compareTo(BigDecimal.ZERO) == 0) {// 避免除数为0
					orderProdPay = new BigDecimal("1");
				}
				if (null != opds && opds.size() > 0) {
					for (OrderProductDetail opd : opds) {
						if (j < opds.size() - 1) {
							if (op.getBonus().compareTo(BigDecimal.ZERO) == 1) {
								_bonus = op.getBonus().multiply(opd.getAmount()).divide(op.getTotalPrice(), dot,
										BigDecimal.ROUND_CEILING);
								remainderDetailBonus = remainderDetailBonus.add(_bonus);
								if (remainderDetailBonus.compareTo(op.getBonus()) == 1) {
									remainderDetailBonus = remainderDetailBonus.subtract(_bonus);
									_bonus = op.getBonus().subtract(remainderDetailBonus);
									remainderDetailBonus = op.getBonus();
								}
								opd.setBonus(_bonus);
							} else {
								opd.setBonus(BigDecimal.ZERO);
							}
							if (opDiscountTypes.contains(opd.getDetailTp())) {
								if (op.getDiscount().compareTo(BigDecimal.ZERO) == 1) {
									_discount = op.getDiscount().multiply(opd.getAmount()).divide(op.getTotalPrice(), dot,
											BigDecimal.ROUND_CEILING);
									remainderDetailDiscount = remainderDetailDiscount.add(_discount);
									if (remainderDetailDiscount.compareTo(op.getDiscount()) == 1) {
										remainderDetailDiscount = remainderDetailDiscount.subtract(_discount);
										_discount = op.getDiscount().subtract(remainderDetailDiscount);
										remainderDetailDiscount = op.getDiscount();
									}
									opd.setDiscount(_discount);
								} else {
									opd.setDiscount(BigDecimal.ZERO);
								}
							} else {
								opd.setDiscount(BigDecimal.ZERO);
							}
							if (opCouponTypes.contains(opd.getDetailTp())) {
								if (op.getCoupon().compareTo(BigDecimal.ZERO) == 1) {
									if (!"6".equals(opd.getDetailTp())) {
										_coupon = op.getCoupon();
									} else {
										_coupon = op.getCoupon().divide(BigDecimal.valueOf(opds.size()), dot, BigDecimal.ROUND_CEILING);
										if (_coupon.compareTo(opd.getAmount().subtract(opd.getDiscount())) == 1) {
											_coupon = opd.getAmount().subtract(opd.getDiscount());
										}
									}
									opd.setCoupon(_coupon);
									remainderDetailCoupon = remainderDetailCoupon.add(_coupon);
								} else {
									opd.setCoupon(BigDecimal.ZERO);
								}
							} else {
								opd.setCoupon(BigDecimal.ZERO);
							}
							orderDetailPay = opd.getAmount().subtract(opd.getBonus()).subtract(opd.getDiscount()).subtract(
									opd.getCoupon());
							if (orderDetailPay.compareTo(BigDecimal.ZERO) == 0) {// 避免除数为0
								orderDetailPay = new BigDecimal("1");
							}
							if (op.getShipfare().compareTo(BigDecimal.ZERO) == 1) {
								_shipfare = op.getShipfare().multiply(orderDetailPay).divide(orderProdPay, dot,
										BigDecimal.ROUND_CEILING);
								remainderDetailShipfare = remainderDetailShipfare.add(_shipfare);
								if (remainderDetailShipfare.compareTo(op.getShipfare()) == 1) {
									remainderDetailShipfare = remainderDetailShipfare.subtract(_shipfare);
									_shipfare = op.getShipfare().subtract(remainderDetailShipfare);
									remainderDetailShipfare = op.getShipfare();
								}
								opd.setShipfare(_shipfare);
							} else {
								opd.setShipfare(BigDecimal.ZERO);
							}
							if (op.getCodFee().compareTo(BigDecimal.ZERO) == 1) {
								_codfee = op.getCodFee().multiply(orderDetailPay).divide(orderProdPay, dot, BigDecimal.ROUND_CEILING);
								remainderDetailCodFee = remainderDetailCodFee.add(_codfee);
								if (remainderDetailCodFee.compareTo(op.getCodFee()) == 1) {
									remainderDetailCodFee = remainderDetailCodFee.subtract(_codfee);
									_codfee = op.getCodFee().subtract(remainderDetailCodFee);
									remainderDetailCodFee = op.getCodFee();
								}
								opd.setCodFee(_codfee);
							} else {
								opd.setCodFee(BigDecimal.ZERO);
							}
							if (op.getInstallmentFee().compareTo(BigDecimal.ZERO) == 1) {
								_installment = op.getInstallmentFee().multiply(orderDetailPay).divide(orderProdPay, dot,
										BigDecimal.ROUND_CEILING);
								remainderDetailInstallmentFee = remainderDetailInstallmentFee.add(_installment);
								if (remainderDetailInstallmentFee.compareTo(op.getInstallmentFee()) == 1) {
									remainderDetailInstallmentFee = remainderDetailInstallmentFee.subtract(_installment);
									_installment = op.getInstallmentFee().subtract(remainderDetailInstallmentFee);
									remainderDetailInstallmentFee = op.getInstallmentFee();
								}
								opd.setInstallmentFee(_installment);
							} else {
								opd.setInstallmentFee(BigDecimal.ZERO);
							}

							if (op.getMustPay().compareTo(BigDecimal.ZERO) == 1) {
								if (op.getMyWallet().compareTo(BigDecimal.ZERO) == 0
										&& op.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 0) {
									_mustPay = opd.getAmount().subtract(opd.getCoupon()).subtract(opd.getDiscount()).subtract(
											opd.getBonus()).add(opd.getShipfare()).add(opd.getCodFee()).add(opd.getInstallmentFee());
								} else {
									_mustPay = op.getMustPay().multiply(orderDetailPay).divide(orderProdPay, dot,
											BigDecimal.ROUND_CEILING);
								}
								remainderDetailMustPay = remainderDetailMustPay.add(_mustPay);
								if (remainderDetailMustPay.compareTo(op.getMustPay()) == 1) {
									remainderDetailMustPay = remainderDetailMustPay.subtract(_mustPay);
									_mustPay = op.getMustPay().subtract(remainderDetailMustPay);
									remainderDetailMustPay = op.getMustPay();
								}
								opd.setMustPay(_mustPay);
							} else {
								opd.setMustPay(BigDecimal.ZERO);
							}
							if (op.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 1
									&& op.getMyWallet().compareTo(BigDecimal.ZERO) == 0) {// 使用礼品卡不使用账户余额支付
								_giftcard = opd.getAmount().subtract(opd.getCoupon()).subtract(opd.getDiscount()).subtract(
										opd.getBonus()).subtract(opd.getMyWallet()).subtract(opd.getMustPay()).add(opd.getShipfare()).add(
										opd.getCodFee()).add(opd.getInstallmentFee());
								remainderDetailGiftcardBalance = remainderDetailGiftcardBalance.add(_giftcard);
								if (remainderDetailGiftcardBalance.compareTo(op.getGiftcardBalance()) == 1) {
									remainderDetailGiftcardBalance = remainderDetailGiftcardBalance.subtract(_giftcard);
									_giftcard = op.getGiftcardBalance().subtract(remainderDetailGiftcardBalance);
									remainderDetailGiftcardBalance = op.getGiftcardBalance();
								}
								opd.setGiftcardBalance(_giftcard);
							} else {
								opd.setGiftcardBalance(BigDecimal.ZERO);
							}
							if (op.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 0
									&& op.getMyWallet().compareTo(BigDecimal.ZERO) == 1) {// 使用账户余额不使用礼品卡支付
								_myWallet = opd.getAmount().subtract(opd.getCoupon()).subtract(opd.getDiscount()).subtract(
										opd.getBonus()).subtract(opd.getMustPay()).add(opd.getShipfare()).add(opd.getCodFee()).add(
										opd.getInstallmentFee());
								remainderDetailMywallet = remainderDetailMywallet.add(_myWallet);
								if (remainderDetailMywallet.compareTo(op.getMyWallet()) == 1) {
									remainderDetailMywallet = remainderDetailMywallet.subtract(_myWallet);
									_myWallet = op.getMyWallet().subtract(remainderDetailMywallet);
									remainderDetailMywallet = op.getMyWallet();
								}
								opd.setMyWallet(_myWallet);
							} else {
								opd.setMyWallet(BigDecimal.ZERO);
							}
							if (op.getGiftcardBalance().compareTo(BigDecimal.ZERO) == 1
									&& op.getMyWallet().compareTo(BigDecimal.ZERO) == 1) {// 使用礼品卡和账户余额支付
								_myWallet = op.getMyWallet().multiply(orderDetailPay).divide(orderProdPay, dot,
										BigDecimal.ROUND_CEILING);
								remainderDetailMywallet = remainderDetailMywallet.add(_myWallet);
								if (remainderDetailMywallet.compareTo(op.getMyWallet()) == 1) {
									remainderDetailMywallet = remainderDetailMywallet.subtract(_myWallet);
									_myWallet = op.getMyWallet().subtract(remainderDetailMywallet);
									remainderDetailMywallet = op.getMyWallet();
								}
								opd.setMyWallet(_myWallet);
								_giftcard = opd.getAmount().subtract(opd.getCoupon()).subtract(opd.getDiscount()).subtract(
										opd.getBonus()).subtract(opd.getMyWallet()).subtract(opd.getMustPay()).add(opd.getShipfare()).add(
										opd.getCodFee()).add(opd.getInstallmentFee());
								remainderDetailGiftcardBalance = remainderDetailGiftcardBalance.add(_giftcard);
								if (remainderDetailGiftcardBalance.compareTo(op.getGiftcardBalance()) == 1) {
									remainderDetailGiftcardBalance = remainderDetailGiftcardBalance.subtract(_giftcard);
									_giftcard = op.getGiftcardBalance().subtract(remainderDetailGiftcardBalance);
									remainderDetailGiftcardBalance = op.getGiftcardBalance();
								}
								opd.setGiftcardBalance(_giftcard);
							}
						} else {
							opd.setGiftcardBalance(op.getGiftcardBalance().subtract(remainderDetailGiftcardBalance));
							opd.setMyWallet(op.getMyWallet().subtract(remainderDetailMywallet));
							opd.setBonus(op.getBonus().subtract(remainderDetailBonus));
							opd.setMustPay(op.getMustPay().subtract(remainderDetailMustPay));
							opd.setShipfare(op.getShipfare().subtract(remainderDetailShipfare));
							opd.setCodFee(op.getCodFee().subtract(remainderDetailCodFee));
							opd.setInstallmentFee(op.getInstallmentFee().subtract(remainderDetailInstallmentFee));
							if (opDiscountTypes.contains(opd.getDetailTp())) {
								opd.setDiscount(op.getDiscount().subtract(remainderDetailDiscount));
							} else {
								opd.setDiscount(BigDecimal.ZERO);
							}
							if (opCouponTypes.contains(opd.getDetailTp())) {
								opd.setCoupon(op.getCoupon().subtract(remainderDetailCoupon));
							} else {
								opd.setCoupon(BigDecimal.ZERO);
							}
						}
						j++;
					}
				}
			}
		}
		return order;
	}

	/**
	 * 將未儲存前的order金額由小到大排序,避免订单金额最小的一笔分配到较多的积分
	 * 
	 * @param map
	 * @return
	 */
	Map<String, Orders> sortOrderByValue(Map<String, Orders> map) {
		List<Orders> list = new LinkedList(map.entrySet());
		Collections.sort(list, new Comparator() {
			public int compare(Object o1, Object o2) {
				Orders order1 = (Orders) ((Map.Entry) (o1)).getValue();
				Orders order2 = (Orders) ((Map.Entry) (o2)).getValue();
				BigDecimal op1 = order1.getTotalPrice().subtract(order1.getDiscount());
				BigDecimal op2 = order2.getTotalPrice().subtract(order2.getDiscount());
				return op1.compareTo(op2);
			}
		});
		Map result = new LinkedHashMap();
		for (Iterator it = list.iterator(); it.hasNext();) {
			Map.Entry entry = (Map.Entry) it.next();
			result.put(entry.getKey(), entry.getValue());
		}
		return result;
	}

	// 检查订单积分折抵上限与前端页面传进来的积分是否正确
	@Transactional(readOnly = false)
	void checkBonus(CartOrders cart, BigDecimal bonus, String domainSrc, String channel, Balance balance) {
		BigDecimal totalPrice = cart.getAmount().add(cart.getDiscount());
		BigDecimal discount = cart.getDiscount();
		String mailBody = "";
		// 积分檢查
		if (bonus.compareTo(BigDecimal.ZERO) == 1) {
			BigDecimal orderPrice = totalPrice.subtract(discount);
			BigDecimal iOffset = calcOffsetBonus(domainSrc, channel, balance, orderPrice);// 计算积分折抵上限
			// 会员积分檢查-折抵会员积分與实际折抵会员积分 不可差異大于1
			BigDecimal pageBonus = bonus;
			if ((iOffset.subtract(pageBonus).floatValue() < -1.0)) {
				String fwMail = systemValueMenu.getOptions().get("fw_mail").getMemo1();
				if (StringUtils.isNotBlank(fwMail)) {
					mailBody = "购物车编号：" + cart.getCartId() + ",积分：" + bonus + ",该订单折抵上限： " + iOffset;
					Mail mail = new Mail("积分检查不过", mailBody, fwMail, "");
					mailService.save(mail);
					mailBody = mail.getBody();
				}
				throw new CoreException("积分检查不过＠" + mailBody);
			}
		}
	}

	List<OrderProductDetail> orderProdDetailFilter(OrderProduct orderProduct) {
		List<OrderProductDetail> newOpds = new ArrayList<OrderProductDetail>();
		if (null != orderProduct.getOrderProductDetail() && orderProduct.getOrderProductDetail().size() > 0) {
			int i = 0;
			// 过滤赠品(赠品不分担任何费用)
			for (OrderProductDetail opd : orderProduct.getOrderProductDetail()) {
				if (!"2".equals(opd.getDetailTp())) {
					newOpds.add(i, opd);
					i++;
				}
			}
			if (newOpds.size() > 0) {
				// 依amount排序(递增)
				Collections.sort(newOpds, new Comparator() {
					@Override
					public int compare(Object o1, Object o2) {
						OrderProductDetail opd1 = (OrderProductDetail) o1;
						OrderProductDetail opd2 = (OrderProductDetail) o2;
						return opd1.getAmount().compareTo(opd2.getAmount());
					}
				});
			}
		}
		return newOpds;
	}

	List<OrderProduct> orderProdFilter(Orders order) {
		List<OrderProduct> newOps = new ArrayList<OrderProduct>();
		if (null != order.getOrderProduct() && order.getOrderProduct().size() > 0) {
			int i = 0;
			// 过滤赠品(赠品不分担任何费用)
			for (OrderProduct op : order.getOrderProduct()) {
				if (!"2".equals(op.getProdTp())) {
					newOps.add(i, op);
					i++;
				}
			}
			if (newOps.size() > 0) {
				// 依amount排序(递增)
				Collections.sort(newOps, new Comparator() {
					@Override
					public int compare(Object o1, Object o2) {
						OrderProduct op1 = (OrderProduct) o1;
						OrderProduct op2 = (OrderProduct) o2;
						return op1.getAmount().compareTo(op2.getAmount());
					}
				});
			}
		}
		return newOps;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.order.service.OrderService#saveOrderBonus(com.yaodian100.ec.order.entity.OrderBonusCampaign)
	 */
	@Transactional(readOnly = false)
	public OrderBonusCampaign saveOrderBonus(OrderBonusCampaign orderBonusCampaign) {
		return orderBonusCampaignDao.save(orderBonusCampaign);
	}

	public ObjectDao<OrderBonusCampaign> getOrderBonusCampaignDao() {
		return orderBonusCampaignDao;
	}

	public void setOrderBonusCampaignDao(ObjectDao<OrderBonusCampaign> orderBonusCampaignDao) {
		this.orderBonusCampaignDao = orderBonusCampaignDao;
	}
}